KEY__IMAGEPAIRS__ROWSPAN: 'rowspan',
URL_KEY__SCHEMA_VERSION: 'urlSchemaVersion',
URL_VALUE__SCHEMA_VERSION__CURRENT: 1,
+
+ // Utility constants only used on the client side.
+ ASC: 'asc',
+ DESC: 'desc',
}
})())
$scope.setBSection = $location.search().setBSection;
$scope.loadingMessage = "please wait...";
+ var currSortAsc = true;
+
+
/**
* On initial page load, load a full dictionary of results.
* Once the dictionary is loaded, unhide the page elements so they can
$scope.orderedColumnNames = data[constants.KEY__ROOT__EXTRACOLUMNORDER];
$scope.imagePairs = data[constants.KEY__ROOT__IMAGEPAIRS];
$scope.imageSets = data[constants.KEY__ROOT__IMAGESETS];
+
+ // set the default sort column and make it ascending.
$scope.sortColumnSubdict = constants.KEY__IMAGEPAIRS__DIFFERENCES;
$scope.sortColumnKey = constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF;
+ currSortAsc = true;
$scope.showSubmitAdvancedSettings = false;
$scope.submitAdvancedSettings = {};
// array copies? (For better performance.)
if ($scope.viewingTab == $scope.defaultTab) {
-
- // TODO(epoger): Until we allow the user to reverse sort order,
- // there are certain columns we want to sort in a different order.
- var doReverse = (
- ($scope.sortColumnKey ==
- constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS) ||
- ($scope.sortColumnKey ==
- constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF));
+ var doReverse = !currSortAsc;
$scope.filteredImagePairs =
$filter("orderBy")(
<head>
<title ng-bind="windowTitle"></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
- <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
+ <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.js"></script>
<script src="constants.js"></script>
<script src="live-loader.js"></script>
<script src="utils.js"></script>
<tr>
<!-- Most column headers are displayed in a common fashion... -->
<th ng-repeat="columnName in orderedColumnNames">
- <input type="radio"
- name="sortColumnRadio"
- value="{{columnName}}"
- ng-checked="(sortColumnKey == columnName)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXTRACOLUMNS, columnName)">
- {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}
+ <a ng-class="'sort-' + sortedByColumnsCls(columnName)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXTRACOLUMNS, columnName)"
+ href=""
+ class="sortable-header">
+ {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}
+ </a>
</th>
<!-- ... but there are a few columns where we display things differently. -->
<th>
- <input type="radio"
- name="sortColumnRadio"
- value="bugs"
- ng-checked="(sortColumnKey == constants.KEY__EXPECTATIONS__BUGS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXPECTATIONS, constants.KEY__EXPECTATIONS__BUGS)">
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__EXPECTATIONS__BUGS)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXPECTATIONS, constants.KEY__EXPECTATIONS__BUGS)"
+ href=""
+ class="sortable-header">
+ bugs
+ </a>
bugs
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="imageA"
- ng-checked="(sortColumnKey == constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
+ ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
+ href=""
+ class="sortable-header">
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ </a>
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="imageB"
- ng-checked="(sortColumnKey == constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
+ ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
+ href=""
+ class="sortable-header">
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ </a>
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="percentDifferingPixels"
- ng-checked="(sortColumnKey == constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)">
- differing pixels in white
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
+ href=""
+ class="sortable-header">
+ differing pixels in white
+ </a>
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="perceptualDiff"
- ng-checked="(sortColumnKey == constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)">
- perceptual difference
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
+ href=""
+ class="sortable-header">
+ perceptual difference
+ </a>
<br>
<input type="range" ng-model="pixelDiffBgColorBrightness"
ng-init="pixelDiffBgColorBrightness=64; pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"
$scope.resultsToLoad = $location.search().resultsToLoad;
$scope.loadingMessage = "please wait...";
+ var currSortAsc = true;
+
+
/**
* On initial page load, load a full dictionary of results.
* Once the dictionary is loaded, unhide the page elements so they can
$scope.orderedColumnNames = data[constants.KEY__ROOT__EXTRACOLUMNORDER];
$scope.imagePairs = data[constants.KEY__ROOT__IMAGEPAIRS];
$scope.imageSets = data[constants.KEY__ROOT__IMAGESETS];
+
+ // set the default sort column and make it ascending.
$scope.sortColumnSubdict = constants.KEY__IMAGEPAIRS__DIFFERENCES;
$scope.sortColumnKey = constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF;
+ currSortAsc = true;
$scope.showSubmitAdvancedSettings = false;
$scope.submitAdvancedSettings = {};
$scope.toggleValueInArray(index, $scope.selectedImagePairs);
}
}
- }
+ };
/**
* Deselect all currently showing tests.
$scope.toggleValueInArray(index, $scope.selectedImagePairs);
}
}
- }
+ };
/**
* Toggle selection of all currently showing tests.
var index = $scope.limitedImagePairs[i].index;
$scope.toggleValueInArray(index, $scope.selectedImagePairs);
}
- }
+ };
/**
* Toggle selection state of a subset of the currently showing tests.
var index = $scope.limitedImagePairs[i].index;
$scope.toggleValueInArray(index, $scope.selectedImagePairs);
}
- }
+ };
//
$scope.setViewingTab = function(tab) {
$scope.viewingTab = tab;
$scope.updateResults();
- }
+ };
/**
* Move the imagePairs in $scope.selectedImagePairs to a different tab,
$scope.moveImagePairsToTab($scope.selectedImagePairs, newTab);
$scope.selectedImagePairs = [];
$scope.updateResults();
- }
+ };
/**
* Move a subset of $scope.imagePairs to a different tab.
$scope.imagePairs[imagePairIndex].tab = newTab;
}
$scope.numResultsPerTab[newTab] += numImagePairs;
- }
+ };
//
// another copy of the array. Is there a way we can filter out
// the imagePairs as they are displayed, rather than storing multiple
// array copies? (For better performance.)
-
if ($scope.viewingTab == $scope.defaultTab) {
-
- // TODO(epoger): Until we allow the user to reverse sort order,
- // there are certain columns we want to sort in a different order.
- var doReverse = (
- ($scope.sortColumnKey ==
- constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS) ||
- ($scope.sortColumnKey ==
- constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF));
+ var doReverse = !currSortAsc;
$scope.filteredImagePairs =
$filter("orderBy")(
$scope.showingColumnValues,
$scope.viewingTab
),
- [$scope.getSortColumnValue, $scope.getSecondOrderSortValue],
+ // [$scope.getSortColumnValue, $scope.getSecondOrderSortValue],
+ $scope.getSortColumnValue,
doReverse);
$scope.limitedImagePairs = $filter("mergeAndLimit")(
$scope.filteredImagePairs, $scope.displayLimit, $scope.mergeIdenticalRows);
{tab: $scope.viewingTab},
true
),
- [$scope.getSortColumnValue, $scope.getSecondOrderSortValue]);
+ // [$scope.getSortColumnValue, $scope.getSecondOrderSortValue]);
+ $scope.getSortColumnValue);
$scope.limitedImagePairs = $filter("mergeAndLimit")(
$scope.filteredImagePairs, -1, $scope.mergeIdenticalRows);
}
$scope.resultsUpdatedCallback = function() {
$scope.renderEndTime = window.performance.now();
$log.debug("renderEndTime: " + $scope.renderEndTime);
- }
+ };
/**
* Re-sort the displayed results.
* @param key (string): sort by value associated with this key in subdict
*/
$scope.sortResultsBy = function(subdict, key) {
- $scope.sortColumnSubdict = subdict;
- $scope.sortColumnKey = key;
+ // if we are already sorting by this column then toggle between asc/desc
+ if ((subdict === $scope.sortColumnSubdict) && ($scope.sortColumnKey === key)) {
+ currSortAsc = !currSortAsc;
+ } else {
+ $scope.sortColumnSubdict = subdict;
+ $scope.sortColumnKey = key;
+ currSortAsc = true;
+ }
$scope.updateResults();
- }
+ };
+
+ /**
+ * Returns ASC or DESC (from constants) if currently the data
+ * is sorted by the provided column.
+ *
+ * @param colName: name of the column for which we need to get the class.
+ */
+
+ $scope.sortedByColumnsCls = function (colName) {
+ if ($scope.sortColumnKey !== colName) {
+ return '';
+ }
+
+ var result = (currSortAsc) ? constants.ASC : constants.DESC;
+ console.log("sort class:", result);
+ return result;
+ };
/**
* For a particular ImagePair, return the value of the column we are
} else {
return undefined;
}
- }
+ };
/**
* For a particular ImagePair, return the value we use for the
$scope.getSecondOrderSortValue = function(imagePair) {
return imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" +
imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
- }
+ };
/**
* Set $scope.columnStringMatch[name] = value, and update results.
$scope.setColumnStringMatch = function(name, value) {
$scope.columnStringMatch[name] = value;
$scope.updateResults();
- }
+ };
/**
* Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName]
$scope.showingColumnValues[columnName] = {};
$scope.toggleValueInSet(columnValue, $scope.showingColumnValues[columnName]);
$scope.updateResults();
- }
+ };
/**
* Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName]
$scope.toggleValuesInSet($scope.allColumnValues[columnName],
$scope.showingColumnValues[columnName]);
$scope.updateResults();
- }
+ };
//
"Please see server-side log for details.");
$scope.submitPending = false;
});
- }
+ };
//
*/
$scope.setSize = function(set) {
return Object.keys(set).length;
- }
+ };
/**
* Returns true if value "value" is present within set "set".
*/
$scope.isValueInSet = function(value, set) {
return (true == set[value]);
- }
+ };
/**
* If value "value" is already in set "set", remove it; otherwise, add it.
} else {
set[value] = true;
}
- }
+ };
/**
* For each value in valueArray, call toggleValueInSet(value, set).
for (var i = 0; i < arrayLength; i++) {
$scope.toggleValueInSet(valueArray[i], set);
}
- }
+ };
//
*/
$scope.isValueInArray = function(value, array) {
return (-1 != array.indexOf(value));
- }
+ };
/**
* If value "value" is already in array "array", remove it; otherwise,
} else {
array.splice(i, 1);
}
- }
+ };
//
slice.push(array[row][column]);
}
return slice;
- }
+ };
/**
* Returns a human-readable (in local time zone) time string for a
$scope.localTimeString = function(secondsPastEpoch) {
var d = new Date(secondsPastEpoch * 1000);
return d.toString();
- }
+ };
/**
* Returns a hex color string (such as "#aabbcc") for the given RGB values.
bString = "0" + bString;
}
return '#' + rString + gString + bString;
- }
+ };
/**
* Returns a hex color string (such as "#aabbcc") for the given brightness.
$scope.brightnessStringToHexColor = function(brightnessString) {
var v = parseInt(brightnessString);
return $scope.hexColorString(v, v, v);
- }
+ };
/**
* Returns the last path component of image diff URL for a given ImagePair.
imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" +
imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL];
return before.replace(/[^\w\-]/g, "_") + ".png";
- }
+ };
}
);
padding: 10px;
border: 2px solid #222;
}
+
+.sort-desc {
+ background:no-repeat left center url(data:image/gif;base64,R0lGODlhCgAKALMAAHFxcYKCgp2dnaampq+vr83NzeHh4f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAAAgAIf/8SUNDUkdCRzEwMTIAAAUwYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkc2NtAAABCAAAAvJkZXNjAAAD/AAAAG9nWFlaAAAEbAAAABR3dHB0AAAEgAAAABRyWFlaAAAElAAAABRiWFlaAAAEqAAAABRyVFJDAAAEvAAAAA5jcHJ0AAAEzAAAADhjaGFkAAAFBAAAACxn/1RSQwAABLwAAAAOYlRSQwAABLwAAAAObWx1YwAAAAAAAAARAAAADGVuVVMAAAAmAAACfmVzRVMAAAAmAAABgmRhREsAAAAuAAAB6mRlREUAAAAsAAABqGZpRkkAAAAoAAAA3GZyRlUAAAAoAAABKml0SVQAAAAoAAACVm5sTkwAAAAoAAACGG5iTk8AAAAmAAABBHB0QlIAAAAmAAABgnN2U0UAAAAmAAABBGphSlAAAAAaAAABUmtvS1IAAAAWAAACQHpoVFcAAAAWAAABbHpoQ04AAAAWAAAB1HJ1UlUAAAAiAAACpHBsUEwAAAAsAAACxgBZAGwAZQBpAG4AZf8AbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAHMAawAgAFIARwBCAC0AcAByAG8AZgBpAGwAUAByAG8AZgBpAGwAIABHAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCTgCCLAAgAFIARwBCACAw1zDtMNUwoTCkMOuQGnUoACAAUgBHAEIAIIJyX2ljz4/wAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8AQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbGZukBoAIABSAEcAQgAgY8+P8GX/h072AEcAZQBuAGUAcgBlAGwAIABSAEcAQgAtAGIAZQBzAGsAcgBpAHYAZQBsAHMAZQBBAGwAZwBlAG0AZQBlAG4AIABSAEcAQgAtAHAAcgBvAGYAaQBlAGzHfLwYACAAUgBHAEIAINUEuFzTDMd8AFAAcgBvAGYAaQBsAG8AIABSAEcAQgAgAEcAZQBuAGUAcgBpAGMAbwBHAGUAbgBlAHIAaQBjACAAUgBHAEIAIABQAHIAbwBmAGkAbABlBB4EMQRJBDgEOQAgBD8EQAQ+BEQEOAQ7BEwAIABSAEcAQgBVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBm/wBpAGwAIABSAEcAQgAAZGVzYwAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAFEdlbmVyaWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAAPNSAAEAAAABFs9YWVogAAAAAAAAdE0AAD3uAAAD0FhZWiAAAAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAAAAABAc0AAHRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUgSW5jLkMsIGFsbCByaWdodHMgcmVzZXJ2ZWQuAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsACwAAAAACgAKAAAEJZAMIcakQZjNtyhFxwEIIRofAookUnapu26t+6KFLYe1TgQ5VwQAOw%3D%3D);
+}
+
+.sort-asc {
+ background:no-repeat left center url(data:image/gif;base64,R0lGODlhCgAKALMAAHFxcYKCgp2dnaampq+vr83NzeHh4f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAAAgAIf/8SUNDUkdCRzEwMTIAAAUwYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkc2NtAAABCAAAAvJkZXNjAAAD/AAAAG9nWFlaAAAEbAAAABR3dHB0AAAEgAAAABRyWFlaAAAElAAAABRiWFlaAAAEqAAAABRyVFJDAAAEvAAAAA5jcHJ0AAAEzAAAADhjaGFkAAAFBAAAACxn/1RSQwAABLwAAAAOYlRSQwAABLwAAAAObWx1YwAAAAAAAAARAAAADGVuVVMAAAAmAAACfmVzRVMAAAAmAAABgmRhREsAAAAuAAAB6mRlREUAAAAsAAABqGZpRkkAAAAoAAAA3GZyRlUAAAAoAAABKml0SVQAAAAoAAACVm5sTkwAAAAoAAACGG5iTk8AAAAmAAABBHB0QlIAAAAmAAABgnN2U0UAAAAmAAABBGphSlAAAAAaAAABUmtvS1IAAAAWAAACQHpoVFcAAAAWAAABbHpoQ04AAAAWAAAB1HJ1UlUAAAAiAAACpHBsUEwAAAAsAAACxgBZAGwAZQBpAG4AZf8AbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAEcAZQBuAGUAcgBpAHMAawAgAFIARwBCAC0AcAByAG8AZgBpAGwAUAByAG8AZgBpAGwAIABHAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCTgCCLAAgAFIARwBCACAw1zDtMNUwoTCkMOuQGnUoACAAUgBHAEIAIIJyX2ljz4/wAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8AQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAAUgBHAEIALQBQAHIAbwBmAGkAbGZukBoAIABSAEcAQgAgY8+P8GX/h072AEcAZQBuAGUAcgBlAGwAIABSAEcAQgAtAGIAZQBzAGsAcgBpAHYAZQBsAHMAZQBBAGwAZwBlAG0AZQBlAG4AIABSAEcAQgAtAHAAcgBvAGYAaQBlAGzHfLwYACAAUgBHAEIAINUEuFzTDMd8AFAAcgBvAGYAaQBsAG8AIABSAEcAQgAgAEcAZQBuAGUAcgBpAGMAbwBHAGUAbgBlAHIAaQBjACAAUgBHAEIAIABQAHIAbwBmAGkAbABlBB4EMQRJBDgEOQAgBD8EQAQ+BEQEOAQ7BEwAIABSAEcAQgBVAG4AaQB3AGUAcgBzAGEAbABuAHkAIABwAHIAbwBm/wBpAGwAIABSAEcAQgAAZGVzYwAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAFEdlbmVyaWMgUkdCIFByb2ZpbGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABadQAArHMAABc0WFlaIAAAAAAAAPNSAAEAAAABFs9YWVogAAAAAAAAdE0AAD3uAAAD0FhZWiAAAAAAAAAoGgAAFZ8AALg2Y3VydgAAAAAAAAABAc0AAHRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUgSW5jLkMsIGFsbCByaWdodHMgcmVzZXJ2ZWQuAHNmMzIAAAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsACwAAAAACgAKAAAEJRBJREKZsxQDsCSGIVzZFnYTGIqktp7fG46uzAn2TAyCMPC9QAQAOw%3D%3D);
+}
+
+.sortable-header {
+ padding-right: 3px;
+ padding-left: 13px;
+ margin-left: 4px;
+}
<head>
<title ng-bind="windowTitle"></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
- <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
+ <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.js"></script>
<script src="constants.js"></script>
<script src="loader.js"></script>
<script src="utils.js"></script>
<table border="0"><tr><td> <!-- table holding results header + results table -->
</td></tr><tr><td>
- <table border="1" ng-app="diff_viewer"> <!-- results -->
+ <table border="1"> <!-- results -->
<tr>
<!-- Most column headers are displayed in a common fashion... -->
<th ng-repeat="columnName in orderedColumnNames">
- <input type="radio"
- name="sortColumnRadio"
- value="{{columnName}}"
- ng-checked="(sortColumnKey == columnName)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXTRACOLUMNS, columnName)">
- {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}
+ <a ng-class="'sort-' + sortedByColumnsCls(columnName)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXTRACOLUMNS, columnName)"
+ href=""
+ class="sortable-header">
+ {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}
+ </a>
</th>
+
<!-- ... but there are a few columns where we display things differently. -->
<th>
- <input type="radio"
- name="sortColumnRadio"
- value="bugs"
- ng-checked="(sortColumnKey == constants.KEY__EXPECTATIONS__BUGS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXPECTATIONS, constants.KEY__EXPECTATIONS__BUGS)">
- bugs
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__EXPECTATIONS__BUGS)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXPECTATIONS, constants.KEY__EXPECTATIONS__BUGS)"
+ href=""
+ class="sortable-header">
+ bugs
+ </a>
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="imageA"
- ng-checked="(sortColumnKey == constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
+ ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)"
+ href=""
+ class="sortable-header">
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ </a>
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="imageB"
- ng-checked="(sortColumnKey == constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
- ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)">
- {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
+ ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)"
+ href=""
+ class="sortable-header">
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
+ </a>
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="percentDifferingPixels"
- ng-checked="(sortColumnKey == constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)">
- differing pixels in white
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)"
+ href=""
+ class="sortable-header">
+ differing pixels in white
+ </a>
</th>
<th width="{{imageSize}}">
- <input type="radio"
- name="sortColumnRadio"
- value="perceptualDiff"
- ng-checked="(sortColumnKey == constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
- ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)">
- perceptual difference
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)"
+ href=""
+ class="sortable-header">
+ perceptual difference
+ </a>
<br>
<input type="range" ng-model="pixelDiffBgColorBrightness"
ng-init="pixelDiffBgColorBrightness=64; pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)"