diff --git a/app/assets/javascripts/discourse/app/initializers/inject-discourse-objects.js b/app/assets/javascripts/discourse/app/initializers/inject-discourse-objects.js index 9290d94a8a5..0cd4cae3484 100644 --- a/app/assets/javascripts/discourse/app/initializers/inject-discourse-objects.js +++ b/app/assets/javascripts/discourse/app/initializers/inject-discourse-objects.js @@ -1,4 +1,3 @@ -import DiscourseLocation from "discourse/lib/discourse-location"; import Session from "discourse/models/session"; import Site from "discourse/models/site"; import TopicTrackingState, { @@ -34,8 +33,6 @@ export default { const session = Session.current(); app.register("service:session", session, { instantiate: false }); - app.register("location:discourse-location", DiscourseLocation); - startTracking(this.topicTrackingState); }, diff --git a/app/assets/javascripts/discourse/app/lib/discourse-location.js b/app/assets/javascripts/discourse/app/lib/discourse-location.js deleted file mode 100644 index 1fd8a14fbb5..00000000000 --- a/app/assets/javascripts/discourse/app/lib/discourse-location.js +++ /dev/null @@ -1,235 +0,0 @@ -import EmberObject from "@ember/object"; -import { guidFor } from "@ember/object/internals"; -import $ from "jquery"; -import { withoutPrefix } from "discourse-common/lib/get-url"; - -let popstateFired = false; -const supportsHistoryState = window.history && "state" in window.history; -const popstateCallbacks = []; - -function _uuid() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { - let r, v; - /* eslint-disable no-bitwise */ - r = (Math.random() * 16) | 0; - v = c === "x" ? r : (r & 3) | 8; - /* eslint-enable no-bitwise */ - return v.toString(16); - }); -} - -/** - `Ember.DiscourseLocation` implements the location API using the browser's - `history.pushState` API. - - @class DiscourseLocation - @namespace Discourse - @extends @ember/object -*/ -const DiscourseLocation = EmberObject.extend({ - init() { - this._super(...arguments); - - this.set("location", this.location || window.location); - - this.initState(); - }, - - /** - @private - - Used to set state on first call to setURL - - @method initState - */ - initState() { - const history = this.history || window.history; - if (history && history.scrollRestoration) { - history.scrollRestoration = "manual"; - } - - this.set("history", history); - - let url = this.formatURL(this.getURL()); - - if (this.location && this.location.hash) { - url += this.location.hash; - } - - this.replaceState(url); - }, - - /** - Will be pre-pended to path upon state change - - @property rootURL - @default '/' - */ - rootURL: "/", - - /** - @private - - Returns the current `location.pathname` without rootURL - - @method getURL - */ - getURL() { - let url = withoutPrefix(this.location.pathname); - const search = this.location.search || ""; - url += search; - url = url.replace(/\/\//g, "/"); // remove extra slashes - return url; - }, - - /** - @private - - Uses `history.pushState` to update the url without a page reload. - - @method setURL - @param path {String} - */ - setURL(path) { - const state = this.getState(); - path = this.formatURL(path); - - if (state && state.path !== path) { - this.pushState(path); - } - }, - - /** - @private - - Uses `history.replaceState` to update the url without a page reload - or history modification. - - @method replaceURL - @param path {String} - */ - replaceURL(path) { - const state = this.getState(); - path = this.formatURL(path); - - if (!state || state.path !== path) { - this.replaceState(path); - } - }, - - /** - @private - - Get the current `history.state` - Polyfill checks for native browser support and falls back to retrieving - from a private _historyState variable - - @method getState - */ - getState() { - return supportsHistoryState ? this.history.state : this._historyState; - }, - - /** - @private - - Pushes a new state - - @method pushState - @param path {String} - */ - pushState(path) { - const state = { path, uuid: _uuid() }; - - // store state if browser doesn't support `history.state` - if (!supportsHistoryState) { - this._historyState = state; - } else { - this.history.pushState(state, null, path); - } - - // used for webkit workaround - this._previousURL = this.getURL(); - }, - - /** - @private - - Replaces the current state - - @method replaceState - @param path {String} - */ - replaceState(path) { - const state = { path, uuid: _uuid() }; - - // store state if browser doesn't support `history.state` - if (!supportsHistoryState) { - this._historyState = state; - } else { - this.history.replaceState(state, null, path); - } - - // used for webkit workaround - this._previousURL = this.getURL(); - }, - - /** - @private - - Register a callback to be invoked whenever the browser - history changes, including using forward and back buttons. - - @method onUpdateURL - @param callback {Function} - */ - onUpdateURL(callback) { - const guid = guidFor(this); - - $(window).on(`popstate.ember-location-${guid}`, () => { - const url = this.getURL(); - - // Ignore initial page load popstate event in Chrome - if (!popstateFired) { - popstateFired = true; - if (url === this._previousURL) { - return; - } - } - - popstateCallbacks.forEach((cb) => cb(url)); - callback(url); - }); - }, - - /** - @private - - Used when using `{{action}}` helper. The url is always appended to the rootURL. - - @method formatURL - @param url {String} - */ - formatURL(url) { - let rootURL = this.rootURL; - - if (url !== "") { - rootURL = rootURL.replace(/\/$/, ""); - - if (rootURL.length > 0 && url.startsWith(rootURL + "/")) { - rootURL = ""; - } - } - - return rootURL + url; - }, - - willDestroy() { - this._super(...arguments); - - const guid = guidFor(this); - $(window).off(`popstate.ember-location-${guid}`); - }, -}); - -export default DiscourseLocation; diff --git a/app/assets/javascripts/discourse/app/lib/url.js b/app/assets/javascripts/discourse/app/lib/url.js index c9c21ebac68..a15ddf2054c 100644 --- a/app/assets/javascripts/discourse/app/lib/url.js +++ b/app/assets/javascripts/discourse/app/lib/url.js @@ -159,6 +159,8 @@ const DiscourseURL = EmberObject.extend({ path = this.router.currentURL.replace(/#.*$/, "") + path; } + path = withoutPrefix(path); + if (this.router.currentURL !== path) { // Always use replaceState in the next runloop to prevent weird routes changing // while URLs are loading. For example, while a topic loads it sets `currentPost` diff --git a/app/assets/javascripts/discourse/app/mapping-router.js b/app/assets/javascripts/discourse/app/mapping-router.js index 9e2cd7e8776..6844a751554 100644 --- a/app/assets/javascripts/discourse/app/mapping-router.js +++ b/app/assets/javascripts/discourse/app/mapping-router.js @@ -5,7 +5,7 @@ import getURL from "discourse-common/lib/get-url"; import applyRouterHomepageOverrides from "./lib/homepage-router-overrides"; class BareRouter extends EmberRouter { - location = isTesting() ? "none" : "discourse-location"; + location = isTesting() ? "none" : "history"; setupRouter() { const didSetup = super.setupRouter(...arguments);