| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Loader: | 2 * Loader: |
| 3 * Reads GM result reports written out by results.py, and imports | 3 * Reads GM result reports written out by results.py, and imports |
| 4 * them into $scope.extraColumnHeaders and $scope.imagePairs . | 4 * them into $scope.extraColumnHeaders and $scope.imagePairs . |
| 5 */ | 5 */ |
| 6 var Loader = angular.module( | 6 var Loader = angular.module( |
| 7 'Loader', | 7 'Loader', |
| 8 ['ConstantsModule'] | 8 ['ConstantsModule'] |
| 9 ); | 9 ); |
| 10 | 10 |
| (...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 | 659 |
| 660 /** | 660 /** |
| 661 * Re-sort the displayed results. | 661 * Re-sort the displayed results. |
| 662 * | 662 * |
| 663 * @param subdict (string): which KEY__IMAGEPAIRS__* subdictionary | 663 * @param subdict (string): which KEY__IMAGEPAIRS__* subdictionary |
| 664 * the sort column key is within, or 'none' if the sort column | 664 * the sort column key is within, or 'none' if the sort column |
| 665 * key is one of KEY__IMAGEPAIRS__* | 665 * key is one of KEY__IMAGEPAIRS__* |
| 666 * @param key (string): sort by value associated with this key in subdict | 666 * @param key (string): sort by value associated with this key in subdict |
| 667 */ | 667 */ |
| 668 $scope.sortResultsBy = function(subdict, key) { | 668 $scope.sortResultsBy = function(subdict, key) { |
| 669 $scope.sortColumnSubdict = subdict; | 669 // if we are already sorting by this column then toggle between asc/desc |
| 670 $scope.sortColumnKey = key; | 670 if ((subdict === $scope.sortColumnSubdict) && ($scope.sortColumnKey === ke
y)) { |
| 671 currSortAsc = !currSortAsc; |
| 672 } else { |
| 673 $scope.sortColumnSubdict = subdict; |
| 674 $scope.sortColumnKey = key; |
| 675 currSortAsc = true; |
| 676 } |
| 671 $scope.updateResults(); | 677 $scope.updateResults(); |
| 672 } | 678 } |
| 673 | 679 |
| 674 /** | 680 /** |
| 681 * Returns ASC or DESC (from constants) if currently the data |
| 682 * is sorted by the provided column. |
| 683 * |
| 684 * @param colName: name of the column for which we need to get the class. |
| 685 */ |
| 686 |
| 687 $scope.sortedByColumnsCls = function (colName) { |
| 688 if ($scope.sortColumnKey !== colName) { |
| 689 return ''; |
| 690 } |
| 691 |
| 692 var result = (currSortAsc) ? constants.ASC : constants.DESC; |
| 693 console.log("sort class:", result); |
| 694 return result; |
| 695 }; |
| 696 |
| 697 /** |
| 675 * For a particular ImagePair, return the value of the column we are | 698 * For a particular ImagePair, return the value of the column we are |
| 676 * sorting on (according to $scope.sortColumnSubdict and | 699 * sorting on (according to $scope.sortColumnSubdict and |
| 677 * $scope.sortColumnKey). | 700 * $scope.sortColumnKey). |
| 678 * | 701 * |
| 679 * @param imagePair: imagePair to get a column value out of. | 702 * @param imagePair: imagePair to get a column value out of. |
| 680 */ | 703 */ |
| 681 $scope.getSortColumnValue = function(imagePair) { | 704 $scope.getSortColumnValue = function(imagePair) { |
| 682 if ($scope.sortColumnSubdict in imagePair) { | 705 if ($scope.sortColumnSubdict in imagePair) { |
| 683 return imagePair[$scope.sortColumnSubdict][$scope.sortColumnKey]; | 706 return imagePair[$scope.sortColumnSubdict][$scope.sortColumnKey]; |
| 684 } else if ($scope.sortColumnKey in imagePair) { | 707 } else if ($scope.sortColumnKey in imagePair) { |
| 685 return imagePair[$scope.sortColumnKey]; | 708 return imagePair[$scope.sortColumnKey]; |
| 686 } else { | 709 } else { |
| 687 return undefined; | 710 return undefined; |
| 688 } | 711 } |
| 689 } | 712 }; |
| 690 | 713 |
| 691 /** | 714 /** |
| 692 * For a particular ImagePair, return the value we use for the | 715 * For a particular ImagePair, return the value we use for the |
| 693 * second-order sort (tiebreaker when multiple rows have | 716 * second-order sort (tiebreaker when multiple rows have |
| 694 * the same getSortColumnValue()). | 717 * the same getSortColumnValue()). |
| 695 * | 718 * |
| 696 * We join the imageA and imageB urls for this value, so that we merge | 719 * We join the imageA and imageB urls for this value, so that we merge |
| 697 * adjacent rows as much as possible. | 720 * adjacent rows as much as possible. |
| 698 * | 721 * |
| 699 * @param imagePair: imagePair to get a column value out of. | 722 * @param imagePair: imagePair to get a column value out of. |
| 700 */ | 723 */ |
| 701 $scope.getSecondOrderSortValue = function(imagePair) { | 724 $scope.getSecondOrderSortValue = function(imagePair) { |
| 702 return imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" + | 725 return imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" + |
| 703 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]; | 726 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]; |
| 704 } | 727 }; |
| 705 | 728 |
| 706 /** | 729 /** |
| 707 * Set $scope.columnStringMatch[name] = value, and update results. | 730 * Set $scope.columnStringMatch[name] = value, and update results. |
| 708 * | 731 * |
| 709 * @param name | 732 * @param name |
| 710 * @param value | 733 * @param value |
| 711 */ | 734 */ |
| 712 $scope.setColumnStringMatch = function(name, value) { | 735 $scope.setColumnStringMatch = function(name, value) { |
| 713 $scope.columnStringMatch[name] = value; | 736 $scope.columnStringMatch[name] = value; |
| 714 $scope.updateResults(); | 737 $scope.updateResults(); |
| 715 } | 738 }; |
| 716 | 739 |
| 717 /** | 740 /** |
| 718 * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatc
h[columnName] | 741 * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatc
h[columnName] |
| 719 * so that ONLY entries with this columnValue are showing, and update the vi
sible results. | 742 * so that ONLY entries with this columnValue are showing, and update the vi
sible results. |
| 720 * (We update both of those, so we cover both freeform and checkbox filtered
columns.) | 743 * (We update both of those, so we cover both freeform and checkbox filtered
columns.) |
| 721 * | 744 * |
| 722 * @param columnName | 745 * @param columnName |
| 723 * @param columnValue | 746 * @param columnValue |
| 724 */ | 747 */ |
| 725 $scope.showOnlyColumnValue = function(columnName, columnValue) { | 748 $scope.showOnlyColumnValue = function(columnName, columnValue) { |
| 726 $scope.columnStringMatch[columnName] = columnValue; | 749 $scope.columnStringMatch[columnName] = columnValue; |
| 727 $scope.showingColumnValues[columnName] = {}; | 750 $scope.showingColumnValues[columnName] = {}; |
| 728 $scope.toggleValueInSet(columnValue, $scope.showingColumnValues[columnName
]); | 751 $scope.toggleValueInSet(columnValue, $scope.showingColumnValues[columnName
]); |
| 729 $scope.updateResults(); | 752 $scope.updateResults(); |
| 730 } | 753 }; |
| 731 | 754 |
| 732 /** | 755 /** |
| 733 * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatc
h[columnName] | 756 * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatc
h[columnName] |
| 734 * so that ALL entries are showing, and update the visible results. | 757 * so that ALL entries are showing, and update the visible results. |
| 735 * (We update both of those, so we cover both freeform and checkbox filtered
columns.) | 758 * (We update both of those, so we cover both freeform and checkbox filtered
columns.) |
| 736 * | 759 * |
| 737 * @param columnName | 760 * @param columnName |
| 738 */ | 761 */ |
| 739 $scope.showAllColumnValues = function(columnName) { | 762 $scope.showAllColumnValues = function(columnName) { |
| 740 $scope.columnStringMatch[columnName] = ""; | 763 $scope.columnStringMatch[columnName] = ""; |
| 741 $scope.showingColumnValues[columnName] = {}; | 764 $scope.showingColumnValues[columnName] = {}; |
| 742 $scope.toggleValuesInSet($scope.allColumnValues[columnName], | 765 $scope.toggleValuesInSet($scope.allColumnValues[columnName], |
| 743 $scope.showingColumnValues[columnName]); | 766 $scope.showingColumnValues[columnName]); |
| 744 $scope.updateResults(); | 767 $scope.updateResults(); |
| 745 } | 768 }; |
| 746 | 769 |
| 747 | 770 |
| 748 // | 771 // |
| 749 // Operations for sending info back to the server. | 772 // Operations for sending info back to the server. |
| 750 // | 773 // |
| 751 | 774 |
| 752 /** | 775 /** |
| 753 * Tell the server that the actual results of these particular tests | 776 * Tell the server that the actual results of these particular tests |
| 754 * are acceptable. | 777 * are acceptable. |
| 755 * | 778 * |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 845 "finished loading the update results into memory!) and you can " + | 868 "finished loading the update results into memory!) and you can " + |
| 846 "submit more baselines if you want."); | 869 "submit more baselines if you want."); |
| 847 // I don't know why, but if I just call reload() here it doesn't work. | 870 // I don't know why, but if I just call reload() here it doesn't work. |
| 848 // Making a timer call it fixes the problem. | 871 // Making a timer call it fixes the problem. |
| 849 $timeout(function(){location.reload();}, 1); | 872 $timeout(function(){location.reload();}, 1); |
| 850 }).error(function(data, status, headers, config) { | 873 }).error(function(data, status, headers, config) { |
| 851 alert("There was an error submitting your baselines.\n\n" + | 874 alert("There was an error submitting your baselines.\n\n" + |
| 852 "Please see server-side log for details."); | 875 "Please see server-side log for details."); |
| 853 $scope.submitPending = false; | 876 $scope.submitPending = false; |
| 854 }); | 877 }); |
| 855 } | 878 }; |
| 856 | 879 |
| 857 | 880 |
| 858 // | 881 // |
| 859 // Operations we use to mimic Set semantics, in such a way that | 882 // Operations we use to mimic Set semantics, in such a way that |
| 860 // checking for presence within the Set is as fast as possible. | 883 // checking for presence within the Set is as fast as possible. |
| 861 // But getting a list of all values within the Set is not necessarily | 884 // But getting a list of all values within the Set is not necessarily |
| 862 // possible. | 885 // possible. |
| 863 // TODO(epoger): move into a separate .js file? | 886 // TODO(epoger): move into a separate .js file? |
| 864 // | 887 // |
| 865 | 888 |
| 866 /** | 889 /** |
| 867 * Returns the number of values present within set "set". | 890 * Returns the number of values present within set "set". |
| 868 * | 891 * |
| 869 * @param set an Object which we use to mimic set semantics | 892 * @param set an Object which we use to mimic set semantics |
| 870 */ | 893 */ |
| 871 $scope.setSize = function(set) { | 894 $scope.setSize = function(set) { |
| 872 return Object.keys(set).length; | 895 return Object.keys(set).length; |
| 873 } | 896 }; |
| 874 | 897 |
| 875 /** | 898 /** |
| 876 * Returns true if value "value" is present within set "set". | 899 * Returns true if value "value" is present within set "set". |
| 877 * | 900 * |
| 878 * @param value a value of any type | 901 * @param value a value of any type |
| 879 * @param set an Object which we use to mimic set semantics | 902 * @param set an Object which we use to mimic set semantics |
| 880 * (this should make isValueInSet faster than if we used an Array) | 903 * (this should make isValueInSet faster than if we used an Array) |
| 881 */ | 904 */ |
| 882 $scope.isValueInSet = function(value, set) { | 905 $scope.isValueInSet = function(value, set) { |
| 883 return (true == set[value]); | 906 return (true == set[value]); |
| 884 } | 907 }; |
| 885 | 908 |
| 886 /** | 909 /** |
| 887 * If value "value" is already in set "set", remove it; otherwise, add it. | 910 * If value "value" is already in set "set", remove it; otherwise, add it. |
| 888 * | 911 * |
| 889 * @param value a value of any type | 912 * @param value a value of any type |
| 890 * @param set an Object which we use to mimic set semantics | 913 * @param set an Object which we use to mimic set semantics |
| 891 */ | 914 */ |
| 892 $scope.toggleValueInSet = function(value, set) { | 915 $scope.toggleValueInSet = function(value, set) { |
| 893 if (true == set[value]) { | 916 if (true == set[value]) { |
| 894 delete set[value]; | 917 delete set[value]; |
| 895 } else { | 918 } else { |
| 896 set[value] = true; | 919 set[value] = true; |
| 897 } | 920 } |
| 898 } | 921 }; |
| 899 | 922 |
| 900 /** | 923 /** |
| 901 * For each value in valueArray, call toggleValueInSet(value, set). | 924 * For each value in valueArray, call toggleValueInSet(value, set). |
| 902 * | 925 * |
| 903 * @param valueArray | 926 * @param valueArray |
| 904 * @param set | 927 * @param set |
| 905 */ | 928 */ |
| 906 $scope.toggleValuesInSet = function(valueArray, set) { | 929 $scope.toggleValuesInSet = function(valueArray, set) { |
| 907 var arrayLength = valueArray.length; | 930 var arrayLength = valueArray.length; |
| 908 for (var i = 0; i < arrayLength; i++) { | 931 for (var i = 0; i < arrayLength; i++) { |
| 909 $scope.toggleValueInSet(valueArray[i], set); | 932 $scope.toggleValueInSet(valueArray[i], set); |
| 910 } | 933 } |
| 911 } | 934 }; |
| 912 | 935 |
| 913 | 936 |
| 914 // | 937 // |
| 915 // Array operations; similar to our Set operations, but operate on a | 938 // Array operations; similar to our Set operations, but operate on a |
| 916 // Javascript Array so we *can* easily get a list of all values in the Set. | 939 // Javascript Array so we *can* easily get a list of all values in the Set. |
| 917 // TODO(epoger): move into a separate .js file? | 940 // TODO(epoger): move into a separate .js file? |
| 918 // | 941 // |
| 919 | 942 |
| 920 /** | 943 /** |
| 921 * Returns true if value "value" is present within array "array". | 944 * Returns true if value "value" is present within array "array". |
| 922 * | 945 * |
| 923 * @param value a value of any type | 946 * @param value a value of any type |
| 924 * @param array a Javascript Array | 947 * @param array a Javascript Array |
| 925 */ | 948 */ |
| 926 $scope.isValueInArray = function(value, array) { | 949 $scope.isValueInArray = function(value, array) { |
| 927 return (-1 != array.indexOf(value)); | 950 return (-1 != array.indexOf(value)); |
| 928 } | 951 }; |
| 929 | 952 |
| 930 /** | 953 /** |
| 931 * If value "value" is already in array "array", remove it; otherwise, | 954 * If value "value" is already in array "array", remove it; otherwise, |
| 932 * add it. | 955 * add it. |
| 933 * | 956 * |
| 934 * @param value a value of any type | 957 * @param value a value of any type |
| 935 * @param array a Javascript Array | 958 * @param array a Javascript Array |
| 936 */ | 959 */ |
| 937 $scope.toggleValueInArray = function(value, array) { | 960 $scope.toggleValueInArray = function(value, array) { |
| 938 var i = array.indexOf(value); | 961 var i = array.indexOf(value); |
| 939 if (-1 == i) { | 962 if (-1 == i) { |
| 940 array.push(value); | 963 array.push(value); |
| 941 } else { | 964 } else { |
| 942 array.splice(i, 1); | 965 array.splice(i, 1); |
| 943 } | 966 } |
| 944 } | 967 }; |
| 945 | 968 |
| 946 | 969 |
| 947 // | 970 // |
| 948 // Miscellaneous utility functions. | 971 // Miscellaneous utility functions. |
| 949 // TODO(epoger): move into a separate .js file? | 972 // TODO(epoger): move into a separate .js file? |
| 950 // | 973 // |
| 951 | 974 |
| 952 /** | 975 /** |
| 953 * Returns a single "column slice" of a 2D array. | 976 * Returns a single "column slice" of a 2D array. |
| 954 * | 977 * |
| 955 * For example, if array is: | 978 * For example, if array is: |
| 956 * [[A0, A1], | 979 * [[A0, A1], |
| 957 * [B0, B1], | 980 * [B0, B1], |
| 958 * [C0, C1]] | 981 * [C0, C1]] |
| 959 * and index is 0, this this will return: | 982 * and index is 0, this this will return: |
| 960 * [A0, B0, C0] | 983 * [A0, B0, C0] |
| 961 * | 984 * |
| 962 * @param array a Javascript Array | 985 * @param array a Javascript Array |
| 963 * @param column (numeric): index within each row array | 986 * @param column (numeric): index within each row array |
| 964 */ | 987 */ |
| 965 $scope.columnSliceOf2DArray = function(array, column) { | 988 $scope.columnSliceOf2DArray = function(array, column) { |
| 966 var slice = []; | 989 var slice = []; |
| 967 var numRows = array.length; | 990 var numRows = array.length; |
| 968 for (var row = 0; row < numRows; row++) { | 991 for (var row = 0; row < numRows; row++) { |
| 969 slice.push(array[row][column]); | 992 slice.push(array[row][column]); |
| 970 } | 993 } |
| 971 return slice; | 994 return slice; |
| 972 } | 995 }; |
| 973 | 996 |
| 974 /** | 997 /** |
| 975 * Returns a human-readable (in local time zone) time string for a | 998 * Returns a human-readable (in local time zone) time string for a |
| 976 * particular moment in time. | 999 * particular moment in time. |
| 977 * | 1000 * |
| 978 * @param secondsPastEpoch (numeric): seconds past epoch in UTC | 1001 * @param secondsPastEpoch (numeric): seconds past epoch in UTC |
| 979 */ | 1002 */ |
| 980 $scope.localTimeString = function(secondsPastEpoch) { | 1003 $scope.localTimeString = function(secondsPastEpoch) { |
| 981 var d = new Date(secondsPastEpoch * 1000); | 1004 var d = new Date(secondsPastEpoch * 1000); |
| 982 return d.toString(); | 1005 return d.toString(); |
| 983 } | 1006 }; |
| 984 | 1007 |
| 985 /** | 1008 /** |
| 986 * Returns a hex color string (such as "#aabbcc") for the given RGB values. | 1009 * Returns a hex color string (such as "#aabbcc") for the given RGB values. |
| 987 * | 1010 * |
| 988 * @param r (numeric): red channel value, 0-255 | 1011 * @param r (numeric): red channel value, 0-255 |
| 989 * @param g (numeric): green channel value, 0-255 | 1012 * @param g (numeric): green channel value, 0-255 |
| 990 * @param b (numeric): blue channel value, 0-255 | 1013 * @param b (numeric): blue channel value, 0-255 |
| 991 */ | 1014 */ |
| 992 $scope.hexColorString = function(r, g, b) { | 1015 $scope.hexColorString = function(r, g, b) { |
| 993 var rString = r.toString(16); | 1016 var rString = r.toString(16); |
| 994 if (r < 16) { | 1017 if (r < 16) { |
| 995 rString = "0" + rString; | 1018 rString = "0" + rString; |
| 996 } | 1019 } |
| 997 var gString = g.toString(16); | 1020 var gString = g.toString(16); |
| 998 if (g < 16) { | 1021 if (g < 16) { |
| 999 gString = "0" + gString; | 1022 gString = "0" + gString; |
| 1000 } | 1023 } |
| 1001 var bString = b.toString(16); | 1024 var bString = b.toString(16); |
| 1002 if (b < 16) { | 1025 if (b < 16) { |
| 1003 bString = "0" + bString; | 1026 bString = "0" + bString; |
| 1004 } | 1027 } |
| 1005 return '#' + rString + gString + bString; | 1028 return '#' + rString + gString + bString; |
| 1006 } | 1029 }; |
| 1007 | 1030 |
| 1008 /** | 1031 /** |
| 1009 * Returns a hex color string (such as "#aabbcc") for the given brightness. | 1032 * Returns a hex color string (such as "#aabbcc") for the given brightness. |
| 1010 * | 1033 * |
| 1011 * @param brightnessString (string): 0-255, 0 is completely black | 1034 * @param brightnessString (string): 0-255, 0 is completely black |
| 1012 * | 1035 * |
| 1013 * TODO(epoger): It might be nice to tint the color when it's not completely | 1036 * TODO(epoger): It might be nice to tint the color when it's not completely |
| 1014 * black or completely white. | 1037 * black or completely white. |
| 1015 */ | 1038 */ |
| 1016 $scope.brightnessStringToHexColor = function(brightnessString) { | 1039 $scope.brightnessStringToHexColor = function(brightnessString) { |
| 1017 var v = parseInt(brightnessString); | 1040 var v = parseInt(brightnessString); |
| 1018 return $scope.hexColorString(v, v, v); | 1041 return $scope.hexColorString(v, v, v); |
| 1019 } | 1042 }; |
| 1020 | 1043 |
| 1021 /** | 1044 /** |
| 1022 * Returns the last path component of image diff URL for a given ImagePair. | 1045 * Returns the last path component of image diff URL for a given ImagePair. |
| 1023 * | 1046 * |
| 1024 * Depending on which diff this is (whitediffs, pixeldiffs, etc.) this | 1047 * Depending on which diff this is (whitediffs, pixeldiffs, etc.) this |
| 1025 * will be relative to different base URLs. | 1048 * will be relative to different base URLs. |
| 1026 * | 1049 * |
| 1027 * We must keep this function in sync with _get_difference_locator() in | 1050 * We must keep this function in sync with _get_difference_locator() in |
| 1028 * ../imagediffdb.py | 1051 * ../imagediffdb.py |
| 1029 * | 1052 * |
| 1030 * @param imagePair: ImagePair to generate image diff URL for | 1053 * @param imagePair: ImagePair to generate image diff URL for |
| 1031 */ | 1054 */ |
| 1032 $scope.getImageDiffRelativeUrl = function(imagePair) { | 1055 $scope.getImageDiffRelativeUrl = function(imagePair) { |
| 1033 var before = | 1056 var before = |
| 1034 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" + | 1057 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" + |
| 1035 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]; | 1058 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]; |
| 1036 return before.replace(/[^\w\-]/g, "_") + ".png"; | 1059 return before.replace(/[^\w\-]/g, "_") + ".png"; |
| 1037 } | 1060 }; |
| 1038 | 1061 |
| 1039 } | 1062 } |
| 1040 ); | 1063 ); |
| OLD | NEW |