mobile.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // TODO: This file was created by bulk-decaffeinate.
  2. // Sanity-check the conversion and remove this comment.
  3. /*
  4. * decaffeinate suggestions:
  5. * DS102: Remove unnecessary code created because of implicit returns
  6. * DS206: Consider reworking classes to avoid initClass
  7. * DS207: Consider shorter variations of null checks
  8. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
  9. */
  10. app.views.Mobile = class Mobile extends app.View {
  11. static initClass() {
  12. this.className = "_mobile";
  13. this.elements = {
  14. body: "body",
  15. content: "._container",
  16. sidebar: "._sidebar",
  17. docPicker: "._settings ._sidebar",
  18. };
  19. this.shortcuts = { escape: "onEscape" };
  20. this.routes = { after: "afterRoute" };
  21. }
  22. static detect() {
  23. if (Cookies.get("override-mobile-detect") != null) {
  24. return JSON.parse(Cookies.get("override-mobile-detect"));
  25. }
  26. try {
  27. return (
  28. window.matchMedia("(max-width: 480px)").matches ||
  29. window.matchMedia("(max-width: 767px)").matches ||
  30. window.matchMedia("(max-height: 767px) and (max-width: 1024px)")
  31. .matches ||
  32. // Need to sniff the user agent because some Android and Windows Phone devices don't take
  33. // resolution (dpi) into account when reporting device width/height.
  34. (navigator.userAgent.indexOf("Android") !== -1 &&
  35. navigator.userAgent.indexOf("Mobile") !== -1) ||
  36. navigator.userAgent.indexOf("IEMobile") !== -1
  37. );
  38. } catch (error) {
  39. return false;
  40. }
  41. }
  42. static detectAndroidWebview() {
  43. try {
  44. return /(Android).*( Version\/.\.. ).*(Chrome)/.test(navigator.userAgent);
  45. } catch (error) {
  46. return false;
  47. }
  48. }
  49. constructor() {
  50. super(document.documentElement);
  51. }
  52. init() {
  53. $.on($("._search"), "touchend", () => this.onTapSearch());
  54. this.toggleSidebar = $("button[data-toggle-sidebar]");
  55. this.toggleSidebar.removeAttribute("hidden");
  56. $.on(this.toggleSidebar, "click", () => this.onClickToggleSidebar());
  57. this.back = $("button[data-back]");
  58. this.back.removeAttribute("hidden");
  59. $.on(this.back, "click", () => this.onClickBack());
  60. this.forward = $("button[data-forward]");
  61. this.forward.removeAttribute("hidden");
  62. $.on(this.forward, "click", () => this.onClickForward());
  63. this.docPickerTab = $('button[data-tab="doc-picker"]');
  64. this.docPickerTab.removeAttribute("hidden");
  65. $.on(this.docPickerTab, "click", (event) =>
  66. this.onClickDocPickerTab(event),
  67. );
  68. this.settingsTab = $('button[data-tab="settings"]');
  69. this.settingsTab.removeAttribute("hidden");
  70. $.on(this.settingsTab, "click", (event) => this.onClickSettingsTab(event));
  71. app.document.sidebar.search.on("searching", () => this.showSidebar());
  72. this.activate();
  73. }
  74. showSidebar() {
  75. let selection;
  76. if (this.isSidebarShown()) {
  77. window.scrollTo(0, 0);
  78. return;
  79. }
  80. this.contentTop = window.scrollY;
  81. this.content.style.display = "none";
  82. this.sidebar.style.display = "block";
  83. if ((selection = this.findByClass(app.views.ListSelect.activeClass))) {
  84. const scrollContainer =
  85. window.scrollY === this.body.scrollTop
  86. ? this.body
  87. : document.documentElement;
  88. $.scrollTo(selection, scrollContainer, "center");
  89. } else {
  90. window.scrollTo(
  91. 0,
  92. (this.findByClass(app.views.ListFold.activeClass) && this.sidebarTop) ||
  93. 0,
  94. );
  95. }
  96. }
  97. hideSidebar() {
  98. if (!this.isSidebarShown()) {
  99. return;
  100. }
  101. this.sidebarTop = window.scrollY;
  102. this.sidebar.style.display = "none";
  103. this.content.style.display = "block";
  104. window.scrollTo(0, this.contentTop || 0);
  105. }
  106. isSidebarShown() {
  107. return this.sidebar.style.display !== "none";
  108. }
  109. onClickBack() {
  110. return history.back();
  111. }
  112. onClickForward() {
  113. return history.forward();
  114. }
  115. onClickToggleSidebar() {
  116. if (this.isSidebarShown()) {
  117. this.hideSidebar();
  118. } else {
  119. this.showSidebar();
  120. }
  121. }
  122. onClickDocPickerTab(event) {
  123. $.stopEvent(event);
  124. this.showDocPicker();
  125. }
  126. onClickSettingsTab(event) {
  127. $.stopEvent(event);
  128. this.showSettings();
  129. }
  130. showDocPicker() {
  131. window.scrollTo(0, 0);
  132. this.docPickerTab.classList.add("active");
  133. this.settingsTab.classList.remove("active");
  134. this.docPicker.style.display = "block";
  135. this.content.style.display = "none";
  136. }
  137. showSettings() {
  138. window.scrollTo(0, 0);
  139. this.docPickerTab.classList.remove("active");
  140. this.settingsTab.classList.add("active");
  141. this.docPicker.style.display = "none";
  142. this.content.style.display = "block";
  143. }
  144. onTapSearch() {
  145. return window.scrollTo(0, 0);
  146. }
  147. onEscape() {
  148. return this.hideSidebar();
  149. }
  150. afterRoute(route) {
  151. this.hideSidebar();
  152. if (route === "settings") {
  153. this.showDocPicker();
  154. } else {
  155. this.content.style.display = "block";
  156. }
  157. if (page.canGoBack()) {
  158. this.back.removeAttribute("disabled");
  159. } else {
  160. this.back.setAttribute("disabled", "disabled");
  161. }
  162. if (page.canGoForward()) {
  163. this.forward.removeAttribute("disabled");
  164. } else {
  165. this.forward.setAttribute("disabled", "disabled");
  166. }
  167. }
  168. };
  169. app.views.Mobile.initClass();