mobile.js 4.7 KB

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