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 |pagesRangeText|. The ranges are |
Toscano
2013/02/11 21:25:13
|pagesRangeText| -> |pageRangeText|
Vitaly Buka (NO REVIEWS)
2013/02/12 00:46:44
Done.
| |
77 * listed in the order they appear in |pageRangeText| and duplicates are not | |
78 * eliminated. If |pageRangeText| is not valid according or | |
79 * |totalPageCount| undefined null is returned. | |
62 * A valid selection has a parsable format and every page identifier is | 80 * A valid selection has a parsable format and every page identifier is |
63 * <= |totalPageCount| unless wildcards are used (see examples). | 81 * greater the 0 and less or equal to |totalPageCount| unless wildcards are |
82 * used(see examples). | |
64 * Example: "1-4, 9, 3-6, 10, 11" is valid, assuming |totalPageCount| >= 11. | 83 * Example: "1-4, 9, 3-6, 10, 11" is valid, assuming |totalPageCount| >= 11. |
65 * Example: "1-4, 6-6" is valid, assuming |totalPageCount| >= 6. | 84 * Example: "1-4, -6" is valid, assuming |totalPageCount| >= 6. |
66 * Example: "2-" is valid, assuming |totalPageCount| >= 2, means from 2 to the | 85 * Example: "2-" is valid, assuming |totalPageCount| >= 2, means from 2 to the |
67 * end. | 86 * end. |
68 * Example: "1-10000" is valid, regardless of |totalPageCount|, means from 1 to | 87 * Example: "4-2, 11, -6" is invalid. |
69 * the end if |totalPageCount| < 10000. | 88 * Example: "-" is valid, assuming |totalPageCount| >= 1. |
70 * Example: "1-4dsf, 11" is invalid regardless of |totalPageCount|. | 89 * 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. | 90 * @param {string} pageRangeText The text to be checked. |
79 * @param {number} totalPageCount The total number of pages. | 91 * @param {number} totalPageCount The total number of pages. |
80 * @return {boolean} true if the |pageRangeText| is valid. | 92 * @return {Array.<{from: number, to: number}>} An array of page range objects. |
81 */ | 93 */ |
82 function isPageRangeTextValid(pageRangeText, totalPageCount) { | 94 function pageRangeTextToPageRanges(pageRangeText, totalPageCount) { |
83 var regex = /^\s*([0-9]+)\s*-\s*([0-9]*)\s*$/; | 95 if (!totalPageCount) |
84 var successfullyParsed = 0; | 96 return null; |
Toscano
2013/02/11 21:25:13
This is true for initial case right? Where Documen
Vitaly Buka (NO REVIEWS)
2013/02/12 00:46:44
Done.
| |
85 | 97 |
86 // Splitting around commas. | 98 var regex = /^\s*([0-9]*)\s*-\s*([0-9]*)\s*$/; |
87 var parts = pageRangeText.split(/,/); | 99 var parts = pageRangeText.split(/,/); |
88 | 100 |
101 var pageRanges = []; | |
89 for (var i = 0; i < parts.length; ++i) { | 102 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); | 103 var match = parts[i].match(regex); |
93 if (parts[i].length == 0) | 104 if (match) { |
94 continue; | 105 if (!isPositiveInteger(match[1]) && match[1] !== '') |
95 | 106 return null; |
96 if (match && match[1] && isPositiveInteger(match[1])) { | 107 if (!isPositiveInteger(match[2]) && match[2] !== '') |
97 var from = parseInt(match[1], 10); | 108 return null; |
98 var to = isPositiveInteger(match[2]) ? parseInt(match[2], 10) : | 109 var from = match[1] ? parseInt(match[1], 10) : 1; |
99 totalPageCount; | 110 var to = match[2] ? parseInt(match[2], 10) : totalPageCount; |
100 if (from > to || from > totalPageCount) | 111 if (from > to || from > totalPageCount) |
101 return false; | 112 return null; |
102 } else if (!isPositiveInteger(parts[i]) || (totalPageCount != -1 && | 113 pageRanges.push({'from': from, 'to': to}); |
103 parseInt(parts[i], 10) > totalPageCount)) { | 114 } else { |
104 return false; | 115 if (!isPositiveInteger(parts[i])) |
116 return null; | |
117 var singlePageNumber = parseInt(parts[i], 10); | |
118 if (singlePageNumber > totalPageCount) | |
119 return null; | |
120 pageRanges.push({'from': singlePageNumber, 'to': singlePageNumber}); | |
105 } | 121 } |
106 successfullyParsed++; | |
107 } | 122 } |
108 return successfullyParsed > 0; | 123 return pageRanges; |
109 } | 124 } |
110 | 125 |
111 /** | 126 /** |
112 * Returns a list of all pages specified in |pagesRangeText|. The pages are | 127 * Returns a list of pages defined by |pagesRangeText|. The pages are |
113 * listed in the order they appear in |pageRangeText| and duplicates are not | 128 * listed in the order they appear in |pageRangeText| and duplicates are not |
114 * eliminated. If |pageRangeText| is not valid according to | 129 * eliminated. If |pageRangeText| is not valid according or |
115 * isPageRangeTextValid(), or |totalPageCount| is undefined an empty list is | 130 * |totalPageCount| undefined [1,2,...,totalPageCount] is returned. |
116 * returned. | 131 * See pageRangeTextToPageRanges for details. |
117 * @param {string} pageRangeText The text to be checked. | 132 * @param {string} pageRangeText The text to be checked. |
118 * @param {number} totalPageCount The total number of pages. | 133 * @param {number} totalPageCount The total number of pages. |
119 * @return {Array.<number>} A list of all pages. | 134 * @return {Array.<number>} A list of all pages. |
120 */ | 135 */ |
121 function pageRangeTextToPageList(pageRangeText, totalPageCount) { | 136 function pageRangeTextToPageList(pageRangeText, totalPageCount) { |
122 var pageList = []; | 137 var pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount); |
123 if ((totalPageCount && | 138 pageList = []; |
124 !isPageRangeTextValid(pageRangeText, totalPageCount)) || | 139 if (pageRanges) { |
125 !totalPageCount) { | 140 for (var i = 0; i < pageRanges.length; ++i) { |
126 return pageList; | 141 for (var j = pageRanges[i].from; j <= Math.min(pageRanges[i].to, |
127 } | 142 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); | 143 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 } | 144 } |
147 } | 145 } |
148 } | 146 } |
147 if (pageList.length == 0) { | |
148 for (var j = 1; j <= totalPageCount; ++j) | |
149 pageList.push(j); | |
150 } | |
149 return pageList; | 151 return pageList; |
150 } | 152 } |
151 | 153 |
152 /** | 154 /** |
153 * @param {Array.<number>} pageList The list to be processed. | 155 * @param {Array.<number>} pageList The list to be processed. |
154 * @return {Array.<number>} The contents of |pageList| in ascending order and | 156 * @return {Array.<number>} The contents of |pageList| in ascending order and |
155 * without any duplicates. |pageList| is not affected. | 157 * without any duplicates. |pageList| is not affected. |
156 */ | 158 */ |
157 function pageListToPageSet(pageList) { | 159 function pageListToPageSet(pageList) { |
158 var pageSet = []; | 160 var pageSet = []; |
159 if (pageList.length == 0) | 161 if (pageList.length == 0) |
160 return pageSet; | 162 return pageSet; |
161 pageSet = pageList.slice(0); | 163 pageSet = pageList.slice(0); |
162 pageSet.sort(function(a, b) { | 164 pageSet.sort(function(a, b) { |
163 return (/** @type {number} */ a) - (/** @type {number} */ b); | 165 return (/** @type {number} */ a) - (/** @type {number} */ b); |
164 }); | 166 }); |
165 pageSet = removeDuplicates(pageSet); | 167 pageSet = removeDuplicates(pageSet); |
166 return pageSet; | 168 return pageSet; |
167 } | 169 } |
168 | 170 |
169 /** | 171 /** |
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. | 172 * @param {!HTMLElement} element Element to check for visibility. |
191 * @return {boolean} Whether the given element is visible. | 173 * @return {boolean} Whether the given element is visible. |
192 */ | 174 */ |
193 function getIsVisible(element) { | 175 function getIsVisible(element) { |
194 return !element.hidden; | 176 return !element.hidden; |
195 } | 177 } |
196 | 178 |
197 /** | 179 /** |
198 * Shows or hides an element. | 180 * Shows or hides an element. |
199 * @param {!HTMLElement} element Element to show or hide. | 181 * @param {!HTMLElement} element Element to show or hide. |
200 * @param {boolean} isVisible Whether the element should be visible or not. | 182 * @param {boolean} isVisible Whether the element should be visible or not. |
201 */ | 183 */ |
202 function setIsVisible(element, isVisible) { | 184 function setIsVisible(element, isVisible) { |
203 element.hidden = !isVisible; | 185 element.hidden = !isVisible; |
204 } | 186 } |
205 | 187 |
206 /** | 188 /** |
207 * @param {!Array} array Array to check for item. | 189 * @param {!Array} array Array to check for item. |
208 * @param {*} item Item to look for in array. | 190 * @param {*} item Item to look for in array. |
209 * @return {boolean} Whether the item is in the array. | 191 * @return {boolean} Whether the item is in the array. |
210 */ | 192 */ |
211 function arrayContains(array, item) { | 193 function arrayContains(array, item) { |
212 return array.indexOf(item) != -1; | 194 return array.indexOf(item) != -1; |
213 } | 195 } |
OLD | NEW |