diff --git a/app/assets/javascripts/discourse/app/initializers/mobile.js b/app/assets/javascripts/discourse/app/initializers/mobile.js index 029650305d..0c52ba0ac4 100644 --- a/app/assets/javascripts/discourse/app/initializers/mobile.js +++ b/app/assets/javascripts/discourse/app/initializers/mobile.js @@ -1,21 +1,15 @@ -import Mobile from "discourse/lib/mobile"; import { setResolverOption } from "discourse-common/resolver"; import { setResolverOption as setLegacyResolverOption } from "discourse-common/lib/legacy-resolver"; -// Initializes the `Mobile` helper object. +// Initializes the `mobileView` resolver option export default { name: "mobile", after: "inject-objects", initialize(container) { - Mobile.init(); const site = container.lookup("service:site"); - site.set("mobileView", Mobile.mobileView); - site.set("desktopView", !Mobile.mobileView); - site.set("isMobileDevice", Mobile.isMobileDevice); - - setResolverOption("mobileView", Mobile.mobileView); - setLegacyResolverOption("mobileView", Mobile.mobileView); + setResolverOption("mobileView", site.mobileView); + setLegacyResolverOption("mobileView", site.mobileView); }, }; diff --git a/app/assets/javascripts/discourse/app/lib/codeblock-buttons.js b/app/assets/javascripts/discourse/app/lib/codeblock-buttons.js index a17ec51e22..eea8daaa72 100644 --- a/app/assets/javascripts/discourse/app/lib/codeblock-buttons.js +++ b/app/assets/javascripts/discourse/app/lib/codeblock-buttons.js @@ -1,6 +1,5 @@ import { cancel } from "@ember/runloop"; import discourseLater from "discourse-common/lib/later"; -import Mobile from "discourse/lib/mobile"; import { bind } from "discourse-common/utils/decorators"; import showModal from "discourse/lib/show-modal"; import I18n from "I18n"; @@ -117,7 +116,7 @@ export default class CodeblockButtons { if ( this.showFullscreen && - !Mobile.isMobileDevice && + !this.site.isMobileDevice && codeBlock.scrollWidth > codeBlock.clientWidth ) { const fullscreenButton = document.createElement("button"); diff --git a/app/assets/javascripts/discourse/app/lib/mobile.js b/app/assets/javascripts/discourse/app/lib/mobile.js index a35cfcee6d..ea9a35b291 100644 --- a/app/assets/javascripts/discourse/app/lib/mobile.js +++ b/app/assets/javascripts/discourse/app/lib/mobile.js @@ -1,67 +1,35 @@ -import { isTesting } from "discourse-common/config/environment"; +import { getOwner } from "discourse-common/lib/get-owner"; +import deprecated from "discourse-common/lib/deprecated"; -let mobileForced = false; +deprecated( + "`discourse/lib/mobile` import is deprecated. Use `isMobileDevice`, `mobileView`, `forceMobile` properties and `toggleMobileView` method on `site:service`" +); + +function site() { + // Use the "default owner" + return getOwner().lookup("site:service"); +} -// An object that is responsible for logic related to mobile devices. const Mobile = { - isMobileDevice: false, - mobileView: false, + get isMobileDevice() { + return site().isMobileDevice; + }, - init() { - const $html = $("html"); - this.isMobileDevice = mobileForced || $html.hasClass("mobile-device"); - this.mobileView = mobileForced || $html.hasClass("mobile-view"); - - if (isTesting() || mobileForced) { - return; - } - - try { - if (window.location.search.match(/mobile_view=1/)) { - localStorage.mobileView = true; - } - if (window.location.search.match(/mobile_view=0/)) { - localStorage.mobileView = false; - } - if (window.location.search.match(/mobile_view=auto/)) { - localStorage.removeItem("mobileView"); - } - if (localStorage.mobileView) { - let savedValue = localStorage.mobileView === "true"; - if (savedValue !== this.mobileView) { - this.reloadPage(savedValue); - } - } - } catch (err) { - // localStorage may be disabled, just skip this - // you get security errors if it is disabled - } + get mobileView() { + return site().mobileView; }, toggleMobileView() { - try { - if (localStorage) { - localStorage.mobileView = !this.mobileView; - } - } catch (err) { - // localStorage may be disabled, skip - } - this.reloadPage(!this.mobileView); - }, - - reloadPage(mobile) { - window.location.assign( - window.location.pathname + "?mobile_view=" + (mobile ? "1" : "0") - ); + return site().toggleMobileView(); }, }; export function forceMobile() { - mobileForced = true; + site().forceMobile = true; } export function resetMobile() { - mobileForced = false; + site().forceMobile = false; } export default Mobile; diff --git a/app/assets/javascripts/discourse/app/models/site.js b/app/assets/javascripts/discourse/app/models/site.js index 62ea5a9814..fdebe583a2 100644 --- a/app/assets/javascripts/discourse/app/models/site.js +++ b/app/assets/javascripts/discourse/app/models/site.js @@ -11,14 +11,21 @@ import discourseComputed from "discourse-common/utils/decorators"; import { getOwner } from "discourse-common/lib/get-owner"; import { isEmpty } from "@ember/utils"; import { htmlSafe } from "@ember/template"; +import { isTesting } from "discourse-common/config/environment"; +import DiscourseURL from "discourse/lib/url"; const Site = RestModel.extend({ isReadOnly: alias("is_readonly"), + mobileForced: false, + isMobileDevice: false, + mobileView: false, + desktopView: true, init() { this._super(...arguments); this.topicCountDesc = ["topic_count:desc"]; + this._initializeMobileViewInfo(); }, @discourseComputed("notification_types") @@ -139,6 +146,60 @@ const Site = RestModel.extend({ return newCategory; } }, + + toggleMobileView() { + try { + if (localStorage) { + localStorage.mobileView = !this.mobileView; + } + } catch (err) { + // localStorage may be disabled, skip + } + + const url = new URL(document.location); + url.searchParams.set("mobile_view", this.mobileView ? "0" : "1"); + DiscourseURL.redirectAbsolute(url.toString()); + }, + + _initializeMobileViewInfo() { + const { classList } = document.documentElement; + this.isMobileDevice = + this.mobileForced || classList.contains("mobile-device"); + this.mobileView = this.mobileForced || classList.contains("mobile-view"); + this.desktopView = !this.mobileView; + + if (isTesting() || this.mobileForced) { + return; + } + + const url = new URL(document.location); + + try { + switch (url.searchParams.get("mobile_view")) { + case "1": + localStorage.mobileView = true; + break; + case "0": + localStorage.mobileView = false; + break; + case "auto": + localStorage.removeItem("mobileView"); + break; + } + + if (localStorage.mobileView) { + const savedValue = localStorage.mobileView === "true"; + + if (savedValue !== this.mobileView) { + url.searchParams.set("mobile_view", savedValue ? "1" : "0"); + DiscourseURL.redirectAbsolute(url.toString()); + } + } + } catch (err) { + // localStorage may be disabled, just skip this + // you get security errors if it is disabled + } + }, }); Site.reopenClass(Singleton, { diff --git a/app/assets/javascripts/discourse/app/routes/application.js b/app/assets/javascripts/discourse/app/routes/application.js index 558ab27bc1..23159939a4 100644 --- a/app/assets/javascripts/discourse/app/routes/application.js +++ b/app/assets/javascripts/discourse/app/routes/application.js @@ -10,7 +10,6 @@ import { findAll } from "discourse/models/login-method"; import { getOwner } from "discourse-common/lib/get-owner"; import getURL from "discourse-common/lib/get-url"; import logout from "discourse/lib/logout"; -import mobile from "discourse/lib/mobile"; import { inject as service } from "@ember/service"; import { setting } from "discourse/lib/computed"; import showModal from "discourse/lib/show-modal"; @@ -48,7 +47,7 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, { }, toggleMobileView() { - mobile.toggleMobileView(); + this.site.toggleMobileView(); }, toggleSidebar() {