| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @param {string} toTest The string to be tested. | 6 * @param {string} toTest The string to be tested. |
| 7 * @return {boolean} True if |toTest| contains only digits. Leading and trailing | 7 * @return {boolean} True if |toTest| contains only digits. Leading and trailing |
| 8 * whitespace is allowed. | 8 * whitespace is allowed. |
| 9 */ | 9 */ |
| 10 function isInteger(toTest) { | 10 function isInteger(toTest) { |
| 11 var numericExp = /^\s*[0-9]+\s*$/; | 11 var numericExp = /^\s*[0-9]+\s*$/; |
| 12 return numericExp.test(toTest); | 12 return numericExp.test(toTest); |
| 13 } | 13 } |
| 14 | 14 |
| 15 /** | 15 /** |
| 16 * Returns true if |value| is a valid non zero positive integer. | 16 * Returns true if |value| is a valid non zero positive integer. |
| 17 * @param {string} value The string to be tested. | 17 * @param {string} value The string to be tested. |
| 18 * | |
| 19 * @return {boolean} true if the |value| is valid non zero positive integer. | 18 * @return {boolean} true if the |value| is valid non zero positive integer. |
| 20 */ | 19 */ |
| 21 function isPositiveInteger(value) { | 20 function isPositiveInteger(value) { |
| 22 return isInteger(value) && parseInt(value, 10) > 0; | 21 return isInteger(value) && parseInt(value, 10) > 0; |
| 23 } | 22 } |
| 24 | 23 |
| 25 /** | 24 /** |
| 26 * Returns true if the contents of the two arrays are equal. | 25 * Returns true if the contents of the two arrays are equal. |
| 27 * @param {Array} array1 The first array. | 26 * @param {Array.<{from: number, to: number}>} array1 The first array. |
| 28 * @param {Array} array2 The second array. | 27 * @param {Array.<{from: number, to: number}>} array2 The second array. |
| 29 * | |
| 30 * @return {boolean} true if the arrays are equal. | 28 * @return {boolean} true if the arrays are equal. |
| 31 */ | 29 */ |
| 32 function areArraysEqual(array1, array2) { | 30 function areArraysEqual(array1, array2) { |
| 33 if (array1.length != array2.length) | 31 if (array1.length != array2.length) |
| 34 return false; | 32 return false; |
| 35 for (var i = 0; i < array1.length; i++) | 33 for (var i = 0; i < array1.length; i++) |
| 36 if (array1[i] !== array2[i]) | 34 if (array1[i] !== array2[i]) |
| 37 return false; | 35 return false; |
| 38 return true; | 36 return true; |
| 39 } | 37 } |
| 40 | 38 |
| 41 /** | 39 /** |
| 40 * Returns true if the contents of the two page ranges are equal. |
| 41 * @param {Array} array1 The first array. |
| 42 * @param {Array} array2 The second array. |
| 43 * @return {boolean} true if the arrays are equal. |
| 44 */ |
| 45 function areRangesEqual(array1, array2) { |
| 46 if (array1.length != array2.length) |
| 47 return false; |
| 48 for (var i = 0; i < array1.length; i++) |
| 49 if (array1[i].from != array2[i].from || |
| 50 array1[i].to != array2[i].to) { |
| 51 return false; |
| 52 } |
| 53 return true; |
| 54 } |
| 55 |
| 56 /** |
| 42 * Removes duplicate elements from |inArray| and returns a new array. | 57 * Removes duplicate elements from |inArray| and returns a new array. |
| 43 * |inArray| is not affected. It assumes that |inArray| is already sorted. | 58 * |inArray| is not affected. It assumes that |inArray| is already sorted. |
| 44 * @param {Array.<number>} inArray The array to be processed. | 59 * @param {Array.<number>} inArray The array to be processed. |
| 45 * @return {Array.<number>} The array after processing. | 60 * @return {Array.<number>} The array after processing. |
| 46 */ | 61 */ |
| 47 function removeDuplicates(inArray) { | 62 function removeDuplicates(inArray) { |
| 48 var out = []; | 63 var out = []; |
| 49 | 64 |
| 50 if (inArray.length == 0) | 65 if (inArray.length == 0) |
| 51 return out; | 66 return out; |
| 52 | 67 |
| 53 out.push(inArray[0]); | 68 out.push(inArray[0]); |
| 54 for (var i = 1; i < inArray.length; ++i) | 69 for (var i = 1; i < inArray.length; ++i) |
| 55 if (inArray[i] != inArray[i - 1]) | 70 if (inArray[i] != inArray[i - 1]) |
| 56 out.push(inArray[i]); | 71 out.push(inArray[i]); |
| 57 return out; | 72 return out; |
| 58 } | 73 } |
| 59 | 74 |
| 60 /** | 75 /** |
| 61 * Checks if |pageRangeText| represents a valid page selection. | 76 * Returns a list of ranges in |pageRangeText|. The ranges are |
| 77 * listed in the order they appear in |pageRangeText| and duplicates are not |
| 78 * eliminated. If |pageRangeText| is not valid null is returned. |
| 62 * A valid selection has a parsable format and every page identifier is | 79 * A valid selection has a parsable format and every page identifier is |
| 63 * <= |totalPageCount| unless wildcards are used (see examples). | 80 * greater the 0 and less or equal to |totalPageCount| unless wildcards are |
| 81 * used(see examples). |
| 82 * If |totalPageCount| is 0 or undefined function uses impossibly large number |
| 83 * instead. |
| 84 * Wildcard the first number must be larger then 0 and less or equal then |
| 85 * |totalPageCount|. If it's missed then 1 is used as the first number. |
| 86 * Wildcard the second number must be larger then the first number. If it's |
| 87 * missed then |totalPageCount| is used as the second number. |
| 64 * Example: "1-4, 9, 3-6, 10, 11" is valid, assuming |totalPageCount| >= 11. | 88 * Example: "1-4, 9, 3-6, 10, 11" is valid, assuming |totalPageCount| >= 11. |
| 65 * Example: "1-4, 6-6" is valid, assuming |totalPageCount| >= 6. | 89 * Example: "1-4, -6" is valid, assuming |totalPageCount| >= 6. |
| 66 * Example: "2-" is valid, assuming |totalPageCount| >= 2, means from 2 to the | 90 * Example: "2-" is valid, assuming |totalPageCount| >= 2, means from 2 to the |
| 67 * end. | 91 * end. |
| 68 * Example: "1-10000" is valid, regardless of |totalPageCount|, means from 1 to | 92 * Example: "4-2, 11, -6" is invalid. |
| 69 * the end if |totalPageCount| < 10000. | 93 * Example: "-" is valid, assuming |totalPageCount| >= 1. |
| 70 * Example: "1-4dsf, 11" is invalid regardless of |totalPageCount|. | 94 * Example: "1-4dsf, 11" is invalid regardless of |totalPageCount|. |
| 71 * Example: "4-2, 11, -6" is invalid regardless of |totalPageCount|. | |
| 72 * | |
| 73 * Note: If |totalPageCount| is undefined the validation does not take | |
| 74 * |totalPageCount| into account. | |
| 75 * Example: "34853253" is valid. | |
| 76 * Example: "1-4, 9, 3-6, 10, 11" is valid. | |
| 77 * | |
| 78 * @param {string} pageRangeText The text to be checked. | 95 * @param {string} pageRangeText The text to be checked. |
| 79 * @param {number} totalPageCount The total number of pages. | 96 * @param {number} totalPageCount The total number of pages. |
| 80 * @return {boolean} true if the |pageRangeText| is valid. | 97 * @return {Array.<{from: number, to: number}>} An array of page range objects. |
| 81 */ | 98 */ |
| 82 function isPageRangeTextValid(pageRangeText, totalPageCount) { | 99 function pageRangeTextToPageRanges(pageRangeText, totalPageCount) { |
| 83 var regex = /^\s*([0-9]+)\s*-\s*([0-9]*)\s*$/; | 100 var MAX_PAGE_NUMBER = 1000000000; |
| 84 var successfullyParsed = 0; | 101 totalPageCount = totalPageCount ? totalPageCount : MAX_PAGE_NUMBER; |
| 85 | 102 |
| 86 // Splitting around commas. | 103 var regex = /^\s*([0-9]*)\s*-\s*([0-9]*)\s*$/; |
| 87 var parts = pageRangeText.split(/,/); | 104 var parts = pageRangeText.split(/,/); |
| 88 | 105 |
| 106 var pageRanges = []; |
| 89 for (var i = 0; i < parts.length; ++i) { | 107 for (var i = 0; i < parts.length; ++i) { |
| 90 // Removing whitespace. | |
| 91 parts[i] = parts[i].replace(/\s*/g, ''); | |
| 92 var match = parts[i].match(regex); | 108 var match = parts[i].match(regex); |
| 93 if (parts[i].length == 0) | 109 if (match) { |
| 94 continue; | 110 if (!isPositiveInteger(match[1]) && match[1] !== '') |
| 95 | 111 return null; |
| 96 if (match && match[1] && isPositiveInteger(match[1])) { | 112 if (!isPositiveInteger(match[2]) && match[2] !== '') |
| 97 var from = parseInt(match[1], 10); | 113 return null; |
| 98 var to = isPositiveInteger(match[2]) ? parseInt(match[2], 10) : | 114 var from = match[1] ? parseInt(match[1], 10) : 1; |
| 99 totalPageCount; | 115 var to = match[2] ? parseInt(match[2], 10) : totalPageCount; |
| 100 if (from > to || from > totalPageCount) | 116 if (from > to || from > totalPageCount) |
| 101 return false; | 117 return null; |
| 102 } else if (!isPositiveInteger(parts[i]) || (totalPageCount != -1 && | 118 pageRanges.push({'from': from, 'to': to}); |
| 103 parseInt(parts[i], 10) > totalPageCount)) { | 119 } else { |
| 104 return false; | 120 if (!isPositiveInteger(parts[i])) |
| 121 return null; |
| 122 var singlePageNumber = parseInt(parts[i], 10); |
| 123 if (singlePageNumber > totalPageCount) |
| 124 return null; |
| 125 pageRanges.push({'from': singlePageNumber, 'to': singlePageNumber}); |
| 105 } | 126 } |
| 106 successfullyParsed++; | |
| 107 } | 127 } |
| 108 return successfullyParsed > 0; | 128 return pageRanges; |
| 109 } | 129 } |
| 110 | 130 |
| 111 /** | 131 /** |
| 112 * Returns a list of all pages specified in |pagesRangeText|. The pages are | 132 * Returns a list of pages defined by |pagesRangeText|. The pages are |
| 113 * listed in the order they appear in |pageRangeText| and duplicates are not | 133 * listed in the order they appear in |pageRangeText| and duplicates are not |
| 114 * eliminated. If |pageRangeText| is not valid according to | 134 * eliminated. If |pageRangeText| is not valid according or |
| 115 * isPageRangeTextValid(), or |totalPageCount| is undefined an empty list is | 135 * |totalPageCount| undefined [1,2,...,totalPageCount] is returned. |
| 116 * returned. | 136 * See pageRangeTextToPageRanges for details. |
| 117 * @param {string} pageRangeText The text to be checked. | 137 * @param {string} pageRangeText The text to be checked. |
| 118 * @param {number} totalPageCount The total number of pages. | 138 * @param {number} totalPageCount The total number of pages. |
| 119 * @return {Array.<number>} A list of all pages. | 139 * @return {Array.<number>} A list of all pages. |
| 120 */ | 140 */ |
| 121 function pageRangeTextToPageList(pageRangeText, totalPageCount) { | 141 function pageRangeTextToPageList(pageRangeText, totalPageCount) { |
| 122 var pageList = []; | 142 var pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount); |
| 123 if ((totalPageCount && | 143 pageList = []; |
| 124 !isPageRangeTextValid(pageRangeText, totalPageCount)) || | 144 if (pageRanges) { |
| 125 !totalPageCount) { | 145 for (var i = 0; i < pageRanges.length; ++i) { |
| 126 return pageList; | 146 for (var j = pageRanges[i].from; j <= Math.min(pageRanges[i].to, |
| 127 } | 147 totalPageCount); ++j) { |
| 128 | |
| 129 var regex = /^\s*([0-9]+)\s*-\s*([0-9]*)\s*$/; | |
| 130 var parts = pageRangeText.split(/,/); | |
| 131 | |
| 132 for (var i = 0; i < parts.length; ++i) { | |
| 133 var match = parts[i].match(regex); | |
| 134 | |
| 135 if (match && match[1]) { | |
| 136 var from = parseInt(match[1], 10); | |
| 137 var to = match[2] ? parseInt(match[2], 10) : totalPageCount; | |
| 138 | |
| 139 for (var j = from; j <= Math.min(to, totalPageCount); ++j) | |
| 140 pageList.push(j); | 148 pageList.push(j); |
| 141 } else { | |
| 142 var singlePageNumber = parseInt(parts[i], 10); | |
| 143 if (isPositiveInteger(singlePageNumber.toString()) && | |
| 144 singlePageNumber <= totalPageCount) { | |
| 145 pageList.push(singlePageNumber); | |
| 146 } | 149 } |
| 147 } | 150 } |
| 148 } | 151 } |
| 152 if (pageList.length == 0) { |
| 153 for (var j = 1; j <= totalPageCount; ++j) |
| 154 pageList.push(j); |
| 155 } |
| 149 return pageList; | 156 return pageList; |
| 150 } | 157 } |
| 151 | 158 |
| 152 /** | 159 /** |
| 153 * @param {Array.<number>} pageList The list to be processed. | 160 * @param {Array.<number>} pageList The list to be processed. |
| 154 * @return {Array.<number>} The contents of |pageList| in ascending order and | 161 * @return {Array.<number>} The contents of |pageList| in ascending order and |
| 155 * without any duplicates. |pageList| is not affected. | 162 * without any duplicates. |pageList| is not affected. |
| 156 */ | 163 */ |
| 157 function pageListToPageSet(pageList) { | 164 function pageListToPageSet(pageList) { |
| 158 var pageSet = []; | 165 var pageSet = []; |
| 159 if (pageList.length == 0) | 166 if (pageList.length == 0) |
| 160 return pageSet; | 167 return pageSet; |
| 161 pageSet = pageList.slice(0); | 168 pageSet = pageList.slice(0); |
| 162 pageSet.sort(function(a, b) { | 169 pageSet.sort(function(a, b) { |
| 163 return (/** @type {number} */ a) - (/** @type {number} */ b); | 170 return (/** @type {number} */ a) - (/** @type {number} */ b); |
| 164 }); | 171 }); |
| 165 pageSet = removeDuplicates(pageSet); | 172 pageSet = removeDuplicates(pageSet); |
| 166 return pageSet; | 173 return pageSet; |
| 167 } | 174 } |
| 168 | 175 |
| 169 /** | 176 /** |
| 170 * Converts |pageSet| to page ranges. It squashes whenever possible. | |
| 171 * Example: '1-2,3,5-7' becomes 1-3,5-7. | |
| 172 * | |
| 173 * @param {Array.<number>} pageSet The set of pages to be processed. Callers | |
| 174 * should ensure that no duplicates exist. | |
| 175 * @return {Array.<{from: number, to: number}>} An array of page range objects. | |
| 176 */ | |
| 177 function pageSetToPageRanges(pageSet) { | |
| 178 var pageRanges = []; | |
| 179 for (var i = 0; i < pageSet.length; ++i) { | |
| 180 var tempFrom = pageSet[i]; | |
| 181 while (i + 1 < pageSet.length && pageSet[i + 1] == pageSet[i] + 1) | |
| 182 ++i; | |
| 183 var tempTo = pageSet[i]; | |
| 184 pageRanges.push({'from': tempFrom, 'to': tempTo}); | |
| 185 } | |
| 186 return pageRanges; | |
| 187 } | |
| 188 | |
| 189 /** | |
| 190 * @param {!HTMLElement} element Element to check for visibility. | 177 * @param {!HTMLElement} element Element to check for visibility. |
| 191 * @return {boolean} Whether the given element is visible. | 178 * @return {boolean} Whether the given element is visible. |
| 192 */ | 179 */ |
| 193 function getIsVisible(element) { | 180 function getIsVisible(element) { |
| 194 return !element.hidden; | 181 return !element.hidden; |
| 195 } | 182 } |
| 196 | 183 |
| 197 /** | 184 /** |
| 198 * Shows or hides an element. | 185 * Shows or hides an element. |
| 199 * @param {!HTMLElement} element Element to show or hide. | 186 * @param {!HTMLElement} element Element to show or hide. |
| 200 * @param {boolean} isVisible Whether the element should be visible or not. | 187 * @param {boolean} isVisible Whether the element should be visible or not. |
| 201 */ | 188 */ |
| 202 function setIsVisible(element, isVisible) { | 189 function setIsVisible(element, isVisible) { |
| 203 element.hidden = !isVisible; | 190 element.hidden = !isVisible; |
| 204 } | 191 } |
| 205 | 192 |
| 206 /** | 193 /** |
| 207 * @param {!Array} array Array to check for item. | 194 * @param {!Array} array Array to check for item. |
| 208 * @param {*} item Item to look for in array. | 195 * @param {*} item Item to look for in array. |
| 209 * @return {boolean} Whether the item is in the array. | 196 * @return {boolean} Whether the item is in the array. |
| 210 */ | 197 */ |
| 211 function arrayContains(array, item) { | 198 function arrayContains(array, item) { |
| 212 return array.indexOf(item) != -1; | 199 return array.indexOf(item) != -1; |
| 213 } | 200 } |
| OLD | NEW |