ui_utils_spec.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2020 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. var _ui_utils = require("../../web/ui_utils.js");
  24. var _util = require("../../shared/util.js");
  25. var _is_node = require("../../shared/is_node.js");
  26. describe("ui_utils", function () {
  27. describe("binary search", function () {
  28. function isTrue(boolean) {
  29. return boolean;
  30. }
  31. function isGreater3(number) {
  32. return number > 3;
  33. }
  34. it("empty array", function () {
  35. expect((0, _ui_utils.binarySearchFirstItem)([], isTrue)).toEqual(0);
  36. });
  37. it("single boolean entry", function () {
  38. expect((0, _ui_utils.binarySearchFirstItem)([false], isTrue)).toEqual(1);
  39. expect((0, _ui_utils.binarySearchFirstItem)([true], isTrue)).toEqual(0);
  40. });
  41. it("three boolean entries", function () {
  42. expect((0, _ui_utils.binarySearchFirstItem)([true, true, true], isTrue)).toEqual(0);
  43. expect((0, _ui_utils.binarySearchFirstItem)([false, true, true], isTrue)).toEqual(1);
  44. expect((0, _ui_utils.binarySearchFirstItem)([false, false, true], isTrue)).toEqual(2);
  45. expect((0, _ui_utils.binarySearchFirstItem)([false, false, false], isTrue)).toEqual(3);
  46. });
  47. it("three numeric entries", function () {
  48. expect((0, _ui_utils.binarySearchFirstItem)([0, 1, 2], isGreater3)).toEqual(3);
  49. expect((0, _ui_utils.binarySearchFirstItem)([2, 3, 4], isGreater3)).toEqual(2);
  50. expect((0, _ui_utils.binarySearchFirstItem)([4, 5, 6], isGreater3)).toEqual(0);
  51. });
  52. });
  53. describe("getPDFFileNameFromURL", function () {
  54. it("gets PDF filename", function () {
  55. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/file1.pdf")).toEqual("file1.pdf");
  56. expect((0, _ui_utils.getPDFFileNameFromURL)("http://www.example.com/pdfs/file2.pdf")).toEqual("file2.pdf");
  57. });
  58. it("gets fallback filename", function () {
  59. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/file1.txt")).toEqual("document.pdf");
  60. expect((0, _ui_utils.getPDFFileNameFromURL)("http://www.example.com/pdfs/file2.txt")).toEqual("document.pdf");
  61. });
  62. it("gets custom fallback filename", function () {
  63. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/file1.txt", "qwerty1.pdf")).toEqual("qwerty1.pdf");
  64. expect((0, _ui_utils.getPDFFileNameFromURL)("http://www.example.com/pdfs/file2.txt", "qwerty2.pdf")).toEqual("qwerty2.pdf");
  65. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/file3.txt", "")).toEqual("");
  66. });
  67. it("gets fallback filename when url is not a string", function () {
  68. expect((0, _ui_utils.getPDFFileNameFromURL)(null)).toEqual("document.pdf");
  69. expect((0, _ui_utils.getPDFFileNameFromURL)(null, "file.pdf")).toEqual("file.pdf");
  70. });
  71. it("gets PDF filename from URL containing leading/trailing whitespace", function () {
  72. expect((0, _ui_utils.getPDFFileNameFromURL)(" /pdfs/file1.pdf ")).toEqual("file1.pdf");
  73. expect((0, _ui_utils.getPDFFileNameFromURL)(" http://www.example.com/pdfs/file2.pdf ")).toEqual("file2.pdf");
  74. });
  75. it("gets PDF filename from query string", function () {
  76. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/pdfs.html?name=file1.pdf")).toEqual("file1.pdf");
  77. expect((0, _ui_utils.getPDFFileNameFromURL)("http://www.example.com/pdfs/pdf.html?file2.pdf")).toEqual("file2.pdf");
  78. });
  79. it("gets PDF filename from hash string", function () {
  80. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/pdfs.html#name=file1.pdf")).toEqual("file1.pdf");
  81. expect((0, _ui_utils.getPDFFileNameFromURL)("http://www.example.com/pdfs/pdf.html#file2.pdf")).toEqual("file2.pdf");
  82. });
  83. it("gets correct PDF filename when multiple ones are present", function () {
  84. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/file1.pdf?name=file.pdf")).toEqual("file1.pdf");
  85. expect((0, _ui_utils.getPDFFileNameFromURL)("http://www.example.com/pdfs/file2.pdf#file.pdf")).toEqual("file2.pdf");
  86. });
  87. it("gets PDF filename from URI-encoded data", function () {
  88. var encodedUrl = encodeURIComponent("http://www.example.com/pdfs/file1.pdf");
  89. expect((0, _ui_utils.getPDFFileNameFromURL)(encodedUrl)).toEqual("file1.pdf");
  90. var encodedUrlWithQuery = encodeURIComponent("http://www.example.com/pdfs/file.txt?file2.pdf");
  91. expect((0, _ui_utils.getPDFFileNameFromURL)(encodedUrlWithQuery)).toEqual("file2.pdf");
  92. });
  93. it("gets PDF filename from data mistaken for URI-encoded", function () {
  94. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/%AA.pdf")).toEqual("%AA.pdf");
  95. expect((0, _ui_utils.getPDFFileNameFromURL)("/pdfs/%2F.pdf")).toEqual("%2F.pdf");
  96. });
  97. it("gets PDF filename from (some) standard protocols", function () {
  98. expect((0, _ui_utils.getPDFFileNameFromURL)("http://www.example.com/file1.pdf")).toEqual("file1.pdf");
  99. expect((0, _ui_utils.getPDFFileNameFromURL)("https://www.example.com/file2.pdf")).toEqual("file2.pdf");
  100. expect((0, _ui_utils.getPDFFileNameFromURL)("file:///path/to/files/file3.pdf")).toEqual("file3.pdf");
  101. expect((0, _ui_utils.getPDFFileNameFromURL)("ftp://www.example.com/file4.pdf")).toEqual("file4.pdf");
  102. });
  103. it('gets PDF filename from query string appended to "blob:" URL', function () {
  104. if (_is_node.isNodeJS) {
  105. pending("Blob in not supported in Node.js.");
  106. }
  107. var typedArray = new Uint8Array([1, 2, 3, 4, 5]);
  108. var blobUrl = (0, _util.createObjectURL)(typedArray, "application/pdf");
  109. expect(blobUrl.startsWith("blob:")).toEqual(true);
  110. expect((0, _ui_utils.getPDFFileNameFromURL)(blobUrl + "?file.pdf")).toEqual("file.pdf");
  111. });
  112. it('gets fallback filename from query string appended to "data:" URL', function () {
  113. var typedArray = new Uint8Array([1, 2, 3, 4, 5]);
  114. var dataUrl = (0, _util.createObjectURL)(typedArray, "application/pdf", true);
  115. expect(dataUrl.startsWith("data:")).toEqual(true);
  116. expect((0, _ui_utils.getPDFFileNameFromURL)(dataUrl + "?file1.pdf")).toEqual("document.pdf");
  117. expect((0, _ui_utils.getPDFFileNameFromURL)(" " + dataUrl + "?file2.pdf")).toEqual("document.pdf");
  118. });
  119. });
  120. describe("EventBus", function () {
  121. it("dispatch event", function () {
  122. var eventBus = new _ui_utils.EventBus();
  123. var count = 0;
  124. eventBus.on("test", function (evt) {
  125. expect(evt).toEqual(undefined);
  126. count++;
  127. });
  128. eventBus.dispatch("test");
  129. expect(count).toEqual(1);
  130. });
  131. it("dispatch event with arguments", function () {
  132. const eventBus = new _ui_utils.EventBus();
  133. let count = 0;
  134. eventBus.on("test", function (evt) {
  135. expect(evt).toEqual({
  136. abc: 123
  137. });
  138. count++;
  139. });
  140. eventBus.dispatch("test", {
  141. abc: 123
  142. });
  143. expect(count).toEqual(1);
  144. });
  145. it("dispatch different event", function () {
  146. var eventBus = new _ui_utils.EventBus();
  147. var count = 0;
  148. eventBus.on("test", function () {
  149. count++;
  150. });
  151. eventBus.dispatch("nottest");
  152. expect(count).toEqual(0);
  153. });
  154. it("dispatch event multiple times", function () {
  155. var eventBus = new _ui_utils.EventBus();
  156. var count = 0;
  157. eventBus.dispatch("test");
  158. eventBus.on("test", function () {
  159. count++;
  160. });
  161. eventBus.dispatch("test");
  162. eventBus.dispatch("test");
  163. expect(count).toEqual(2);
  164. });
  165. it("dispatch event to multiple handlers", function () {
  166. var eventBus = new _ui_utils.EventBus();
  167. var count = 0;
  168. eventBus.on("test", function () {
  169. count++;
  170. });
  171. eventBus.on("test", function () {
  172. count++;
  173. });
  174. eventBus.dispatch("test");
  175. expect(count).toEqual(2);
  176. });
  177. it("dispatch to detached", function () {
  178. var eventBus = new _ui_utils.EventBus();
  179. var count = 0;
  180. var listener = function () {
  181. count++;
  182. };
  183. eventBus.on("test", listener);
  184. eventBus.dispatch("test");
  185. eventBus.off("test", listener);
  186. eventBus.dispatch("test");
  187. expect(count).toEqual(1);
  188. });
  189. it("dispatch to wrong detached", function () {
  190. var eventBus = new _ui_utils.EventBus();
  191. var count = 0;
  192. eventBus.on("test", function () {
  193. count++;
  194. });
  195. eventBus.dispatch("test");
  196. eventBus.off("test", function () {
  197. count++;
  198. });
  199. eventBus.dispatch("test");
  200. expect(count).toEqual(2);
  201. });
  202. it("dispatch to detached during handling", function () {
  203. var eventBus = new _ui_utils.EventBus();
  204. var count = 0;
  205. var listener1 = function () {
  206. eventBus.off("test", listener2);
  207. count++;
  208. };
  209. var listener2 = function () {
  210. eventBus.off("test", listener1);
  211. count++;
  212. };
  213. eventBus.on("test", listener1);
  214. eventBus.on("test", listener2);
  215. eventBus.dispatch("test");
  216. eventBus.dispatch("test");
  217. expect(count).toEqual(2);
  218. });
  219. it("should not re-dispatch to DOM", function (done) {
  220. if (_is_node.isNodeJS) {
  221. pending("Document in not supported in Node.js.");
  222. }
  223. const eventBus = new _ui_utils.EventBus();
  224. let count = 0;
  225. eventBus.on("test", function (evt) {
  226. expect(evt).toEqual(undefined);
  227. count++;
  228. });
  229. function domEventListener() {
  230. done.fail("shall not dispatch DOM event.");
  231. }
  232. document.addEventListener("test", domEventListener);
  233. eventBus.dispatch("test");
  234. Promise.resolve().then(() => {
  235. expect(count).toEqual(1);
  236. document.removeEventListener("test", domEventListener);
  237. done();
  238. });
  239. });
  240. });
  241. describe("isValidRotation", function () {
  242. it("should reject non-integer angles", function () {
  243. expect((0, _ui_utils.isValidRotation)()).toEqual(false);
  244. expect((0, _ui_utils.isValidRotation)(null)).toEqual(false);
  245. expect((0, _ui_utils.isValidRotation)(NaN)).toEqual(false);
  246. expect((0, _ui_utils.isValidRotation)([90])).toEqual(false);
  247. expect((0, _ui_utils.isValidRotation)("90")).toEqual(false);
  248. expect((0, _ui_utils.isValidRotation)(90.5)).toEqual(false);
  249. });
  250. it("should reject non-multiple of 90 degree angles", function () {
  251. expect((0, _ui_utils.isValidRotation)(45)).toEqual(false);
  252. expect((0, _ui_utils.isValidRotation)(-123)).toEqual(false);
  253. });
  254. it("should accept valid angles", function () {
  255. expect((0, _ui_utils.isValidRotation)(0)).toEqual(true);
  256. expect((0, _ui_utils.isValidRotation)(90)).toEqual(true);
  257. expect((0, _ui_utils.isValidRotation)(-270)).toEqual(true);
  258. expect((0, _ui_utils.isValidRotation)(540)).toEqual(true);
  259. });
  260. });
  261. describe("isPortraitOrientation", function () {
  262. it("should be portrait orientation", function () {
  263. expect((0, _ui_utils.isPortraitOrientation)({
  264. width: 200,
  265. height: 400
  266. })).toEqual(true);
  267. expect((0, _ui_utils.isPortraitOrientation)({
  268. width: 500,
  269. height: 500
  270. })).toEqual(true);
  271. });
  272. it("should be landscape orientation", function () {
  273. expect((0, _ui_utils.isPortraitOrientation)({
  274. width: 600,
  275. height: 300
  276. })).toEqual(false);
  277. });
  278. });
  279. describe("waitOnEventOrTimeout", function () {
  280. let eventBus;
  281. beforeAll(function (done) {
  282. eventBus = new _ui_utils.EventBus();
  283. done();
  284. });
  285. afterAll(function () {
  286. eventBus = null;
  287. });
  288. it("should reject invalid parameters", function (done) {
  289. const invalidTarget = (0, _ui_utils.waitOnEventOrTimeout)({
  290. target: "window",
  291. name: "DOMContentLoaded"
  292. }).then(function () {
  293. throw new Error("Should reject invalid parameters.");
  294. }, function (reason) {
  295. expect(reason instanceof Error).toEqual(true);
  296. });
  297. const invalidName = (0, _ui_utils.waitOnEventOrTimeout)({
  298. target: eventBus,
  299. name: ""
  300. }).then(function () {
  301. throw new Error("Should reject invalid parameters.");
  302. }, function (reason) {
  303. expect(reason instanceof Error).toEqual(true);
  304. });
  305. const invalidDelay = (0, _ui_utils.waitOnEventOrTimeout)({
  306. target: eventBus,
  307. name: "pagerendered",
  308. delay: -1000
  309. }).then(function () {
  310. throw new Error("Should reject invalid parameters.");
  311. }, function (reason) {
  312. expect(reason instanceof Error).toEqual(true);
  313. });
  314. Promise.all([invalidTarget, invalidName, invalidDelay]).then(done, done.fail);
  315. });
  316. it("should resolve on event, using the DOM", function (done) {
  317. if (_is_node.isNodeJS) {
  318. pending("Document in not supported in Node.js.");
  319. }
  320. const button = document.createElement("button");
  321. const buttonClicked = (0, _ui_utils.waitOnEventOrTimeout)({
  322. target: button,
  323. name: "click",
  324. delay: 10000
  325. });
  326. button.click();
  327. buttonClicked.then(function (type) {
  328. expect(type).toEqual(_ui_utils.WaitOnType.EVENT);
  329. done();
  330. }, done.fail);
  331. });
  332. it("should resolve on timeout, using the DOM", function (done) {
  333. if (_is_node.isNodeJS) {
  334. pending("Document in not supported in Node.js.");
  335. }
  336. const button = document.createElement("button");
  337. const buttonClicked = (0, _ui_utils.waitOnEventOrTimeout)({
  338. target: button,
  339. name: "click",
  340. delay: 10
  341. });
  342. buttonClicked.then(function (type) {
  343. expect(type).toEqual(_ui_utils.WaitOnType.TIMEOUT);
  344. done();
  345. }, done.fail);
  346. });
  347. it("should resolve on event, using the EventBus", function (done) {
  348. const pageRendered = (0, _ui_utils.waitOnEventOrTimeout)({
  349. target: eventBus,
  350. name: "pagerendered",
  351. delay: 10000
  352. });
  353. eventBus.dispatch("pagerendered");
  354. pageRendered.then(function (type) {
  355. expect(type).toEqual(_ui_utils.WaitOnType.EVENT);
  356. done();
  357. }, done.fail);
  358. });
  359. it("should resolve on timeout, using the EventBus", function (done) {
  360. const pageRendered = (0, _ui_utils.waitOnEventOrTimeout)({
  361. target: eventBus,
  362. name: "pagerendered",
  363. delay: 10
  364. });
  365. pageRendered.then(function (type) {
  366. expect(type).toEqual(_ui_utils.WaitOnType.TIMEOUT);
  367. done();
  368. }, done.fail);
  369. });
  370. });
  371. describe("getPageSizeInches", function () {
  372. it("gets page size (in inches)", function () {
  373. const page = {
  374. view: [0, 0, 595.28, 841.89],
  375. userUnit: 1.0,
  376. rotate: 0
  377. };
  378. const {
  379. width,
  380. height
  381. } = (0, _ui_utils.getPageSizeInches)(page);
  382. expect(+width.toPrecision(3)).toEqual(8.27);
  383. expect(+height.toPrecision(4)).toEqual(11.69);
  384. });
  385. it("gets page size (in inches), for non-default /Rotate entry", function () {
  386. const pdfPage1 = {
  387. view: [0, 0, 612, 792],
  388. userUnit: 1,
  389. rotate: 0
  390. };
  391. const {
  392. width: width1,
  393. height: height1
  394. } = (0, _ui_utils.getPageSizeInches)(pdfPage1);
  395. expect(width1).toEqual(8.5);
  396. expect(height1).toEqual(11);
  397. const pdfPage2 = {
  398. view: [0, 0, 612, 792],
  399. userUnit: 1,
  400. rotate: 90
  401. };
  402. const {
  403. width: width2,
  404. height: height2
  405. } = (0, _ui_utils.getPageSizeInches)(pdfPage2);
  406. expect(width2).toEqual(11);
  407. expect(height2).toEqual(8.5);
  408. });
  409. });
  410. describe("getVisibleElements", function () {
  411. const BORDER_WIDTH = 9;
  412. const SPACING = 2 * BORDER_WIDTH - 7;
  413. function makePages(lines) {
  414. const result = [];
  415. let lineTop = 0,
  416. id = 0;
  417. for (const line of lines) {
  418. const lineHeight = line.reduce(function (maxHeight, pair) {
  419. return Math.max(maxHeight, pair[1]);
  420. }, 0);
  421. let offsetLeft = -BORDER_WIDTH;
  422. for (const [clientWidth, clientHeight] of line) {
  423. const offsetTop = lineTop + (lineHeight - clientHeight) / 2 - BORDER_WIDTH;
  424. const div = {
  425. offsetLeft,
  426. offsetTop,
  427. clientWidth,
  428. clientHeight,
  429. clientLeft: BORDER_WIDTH,
  430. clientTop: BORDER_WIDTH
  431. };
  432. result.push({
  433. id,
  434. div
  435. });
  436. ++id;
  437. offsetLeft += clientWidth + SPACING;
  438. }
  439. lineTop += lineHeight + SPACING;
  440. }
  441. return result;
  442. }
  443. function slowGetVisibleElements(scroll, pages) {
  444. const views = [];
  445. const {
  446. scrollLeft,
  447. scrollTop
  448. } = scroll;
  449. const scrollRight = scrollLeft + scroll.clientWidth;
  450. const scrollBottom = scrollTop + scroll.clientHeight;
  451. for (const view of pages) {
  452. const {
  453. div
  454. } = view;
  455. const viewLeft = div.offsetLeft + div.clientLeft;
  456. const viewRight = viewLeft + div.clientWidth;
  457. const viewTop = div.offsetTop + div.clientTop;
  458. const viewBottom = viewTop + div.clientHeight;
  459. if (viewLeft < scrollRight && viewRight > scrollLeft && viewTop < scrollBottom && viewBottom > scrollTop) {
  460. const hiddenHeight = Math.max(0, scrollTop - viewTop) + Math.max(0, viewBottom - scrollBottom);
  461. const hiddenWidth = Math.max(0, scrollLeft - viewLeft) + Math.max(0, viewRight - scrollRight);
  462. const visibleArea = (div.clientHeight - hiddenHeight) * (div.clientWidth - hiddenWidth);
  463. const percent = visibleArea * 100 / div.clientHeight / div.clientWidth | 0;
  464. views.push({
  465. id: view.id,
  466. x: viewLeft,
  467. y: viewTop,
  468. view,
  469. percent
  470. });
  471. }
  472. }
  473. return {
  474. first: views[0],
  475. last: views[views.length - 1],
  476. views
  477. };
  478. }
  479. function scrollOverDocument(pages, horizontally = false) {
  480. const size = pages.reduce(function (max, {
  481. div
  482. }) {
  483. return Math.max(max, horizontally ? div.offsetLeft + div.clientLeft + div.clientWidth : div.offsetTop + div.clientTop + div.clientHeight);
  484. }, 0);
  485. for (let i = 0; i < size; i += 7) {
  486. for (let j = i + 5; j < size; j += j - i) {
  487. const scroll = horizontally ? {
  488. scrollTop: 0,
  489. scrollLeft: i,
  490. clientHeight: 10000,
  491. clientWidth: j - i
  492. } : {
  493. scrollTop: i,
  494. scrollLeft: 0,
  495. clientHeight: j - i,
  496. clientWidth: 10000
  497. };
  498. expect((0, _ui_utils.getVisibleElements)(scroll, pages, false, horizontally)).toEqual(slowGetVisibleElements(scroll, pages));
  499. }
  500. }
  501. }
  502. it("with pages of varying height", function () {
  503. const pages = makePages([[[50, 20], [20, 50]], [[30, 12], [12, 30]], [[20, 50], [50, 20]], [[50, 20], [20, 50]]]);
  504. scrollOverDocument(pages);
  505. });
  506. it("widescreen challenge", function () {
  507. const pages = makePages([[[10, 50], [10, 60], [10, 70], [10, 80], [10, 90]], [[10, 90], [10, 80], [10, 70], [10, 60], [10, 50]], [[10, 50], [10, 60], [10, 70], [10, 80], [10, 90]]]);
  508. scrollOverDocument(pages);
  509. });
  510. it("works with horizontal scrolling", function () {
  511. const pages = makePages([[[10, 50], [20, 20], [30, 10]]]);
  512. scrollOverDocument(pages, true);
  513. });
  514. it("handles `sortByVisibility` correctly", function () {
  515. const scrollEl = {
  516. scrollTop: 75,
  517. scrollLeft: 0,
  518. clientHeight: 750,
  519. clientWidth: 1500
  520. };
  521. const views = makePages([[[100, 150]], [[100, 150]], [[100, 150]]]);
  522. const visible = (0, _ui_utils.getVisibleElements)(scrollEl, views);
  523. const visibleSorted = (0, _ui_utils.getVisibleElements)(scrollEl, views, true);
  524. const viewsOrder = [],
  525. viewsSortedOrder = [];
  526. for (const view of visible.views) {
  527. viewsOrder.push(view.id);
  528. }
  529. for (const view of visibleSorted.views) {
  530. viewsSortedOrder.push(view.id);
  531. }
  532. expect(viewsOrder).toEqual([0, 1, 2]);
  533. expect(viewsSortedOrder).toEqual([1, 2, 0]);
  534. });
  535. it("handles views being empty", function () {
  536. const scrollEl = {
  537. scrollTop: 10,
  538. scrollLeft: 0,
  539. clientHeight: 750,
  540. clientWidth: 1500
  541. };
  542. const views = [];
  543. expect((0, _ui_utils.getVisibleElements)(scrollEl, views)).toEqual({
  544. first: undefined,
  545. last: undefined,
  546. views: []
  547. });
  548. });
  549. it("handles all views being hidden (without errors)", function () {
  550. const scrollEl = {
  551. scrollTop: 100000,
  552. scrollLeft: 0,
  553. clientHeight: 750,
  554. clientWidth: 1500
  555. };
  556. const views = makePages([[[100, 150]], [[100, 150]], [[100, 150]]]);
  557. expect((0, _ui_utils.getVisibleElements)(scrollEl, views)).toEqual({
  558. first: undefined,
  559. last: undefined,
  560. views: []
  561. });
  562. });
  563. describe("backtrackBeforeAllVisibleElements", function () {
  564. const tallPage = [10, 50];
  565. const shortPage = [10, 10];
  566. const top1 = 20 + SPACING + 40;
  567. const top2 = 20 + SPACING + 10;
  568. it("handles case 1", function () {
  569. const pages = makePages([[[10, 20], [10, 20], [10, 20], [10, 20]], [tallPage, shortPage, tallPage, shortPage], [[10, 50], [10, 50], [10, 50], [10, 50]], [[10, 20], [10, 20], [10, 20], [10, 20]], [[10, 20]]]);
  570. const bsResult = 4;
  571. expect((0, _ui_utils.backtrackBeforeAllVisibleElements)(bsResult, pages, top1)).toEqual(4);
  572. });
  573. it("handles case 2", function () {
  574. const pages = makePages([[[10, 20], [10, 20], [10, 20], [10, 20]], [tallPage, shortPage, tallPage, tallPage], [[10, 50], [10, 50], [10, 50], [10, 50]], [[10, 20], [10, 20], [10, 20], [10, 20]]]);
  575. const bsResult = 6;
  576. expect((0, _ui_utils.backtrackBeforeAllVisibleElements)(bsResult, pages, top1)).toEqual(4);
  577. });
  578. it("handles case 3", function () {
  579. const pages = makePages([[[10, 20], [10, 20], [10, 20], [10, 20]], [tallPage, shortPage, tallPage, shortPage], [[10, 50], [10, 50], [10, 50], [10, 50]], [[10, 20], [10, 20], [10, 20], [10, 20]]]);
  580. const bsResult = 8;
  581. expect((0, _ui_utils.backtrackBeforeAllVisibleElements)(bsResult, pages, top1)).toEqual(4);
  582. });
  583. it("handles case 4", function () {
  584. const pages = makePages([[[10, 20], [10, 20], [10, 20], [10, 20]], [tallPage, shortPage, tallPage, shortPage], [[10, 50], [10, 50], [10, 50], [10, 50]], [[10, 20], [10, 20], [10, 20], [10, 20]]]);
  585. const bsResult = 4;
  586. expect((0, _ui_utils.backtrackBeforeAllVisibleElements)(bsResult, pages, top2)).toEqual(4);
  587. });
  588. });
  589. });
  590. describe("moveToEndOfArray", function () {
  591. it("works on empty arrays", function () {
  592. const data = [];
  593. (0, _ui_utils.moveToEndOfArray)(data, function () {});
  594. expect(data).toEqual([]);
  595. });
  596. it("works when moving everything", function () {
  597. const data = [1, 2, 3, 4, 5];
  598. (0, _ui_utils.moveToEndOfArray)(data, function () {
  599. return true;
  600. });
  601. expect(data).toEqual([1, 2, 3, 4, 5]);
  602. });
  603. it("works when moving some things", function () {
  604. const data = [1, 2, 3, 4, 5];
  605. (0, _ui_utils.moveToEndOfArray)(data, function (x) {
  606. return x % 2 === 0;
  607. });
  608. expect(data).toEqual([1, 3, 5, 2, 4]);
  609. });
  610. it("works when moving one thing", function () {
  611. const data = [1, 2, 3, 4, 5];
  612. (0, _ui_utils.moveToEndOfArray)(data, function (x) {
  613. return x === 1;
  614. });
  615. expect(data).toEqual([2, 3, 4, 5, 1]);
  616. });
  617. it("works when moving nothing", function () {
  618. const data = [1, 2, 3, 4, 5];
  619. (0, _ui_utils.moveToEndOfArray)(data, function (x) {
  620. return x === 0;
  621. });
  622. expect(data).toEqual([1, 2, 3, 4, 5]);
  623. });
  624. });
  625. });