From 896665b5829dcc68b8961f2a68b8b1d576fbf284 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 23 Mar 2022 09:33:34 +0000 Subject: [PATCH 01/13] issue/2799 Tidy --- templates/header.jsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/templates/header.jsx b/templates/header.jsx index 2aecddbc..276087a0 100644 --- a/templates/header.jsx +++ b/templates/header.jsx @@ -1,6 +1,6 @@ import Adapt from 'core/js/adapt'; import React, { useRef } from 'react'; -import { html, prefixClasses, compile } from 'core/js/reactHelpers'; +import { prefixClasses, compile } from 'core/js/reactHelpers'; /** * Content header for displayTitle, body, instruction text, etc. @@ -49,31 +49,27 @@ export default function Header(props) {
} -
- {html(compile(displayTitle, props))} +
} {_isA11yComponentDescriptionEnabled && ariaRegion && -
- {html(compile(ariaRegion))} +
} {body &&
-
- {html(compile(body, props))} +
} {sizedInstruction &&
-
- {html(compile(sizedInstruction, props))} +
} From e58dd02a0ec1c7b69c55196d08d871711a390382 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 23 Mar 2022 13:55:22 +0000 Subject: [PATCH 02/13] issue/2799 Explicit deprecation warnings, direct imports, fixed circular dependencies --- js/a11y.js | 41 ++- js/a11y/browserFocus.js | 9 +- js/a11y/deprecated.js | 331 +++++++++++------------ js/a11y/keyboardFocusOutline.js | 7 +- js/a11y/log.js | 13 +- js/a11y/popup.js | 25 +- js/a11y/wrapFocus.js | 9 +- js/accessibility.js | 4 +- js/adapt.js | 426 +++++++++++------------------- js/app.js | 15 +- js/childEvent.js | 6 +- js/components.js | 221 ++++++++++++++++ js/data.js | 110 ++++++-- js/deprecated.js | 42 +++ js/device.js | 12 +- js/drawer.js | 10 +- js/fixes/reactHelpers.html.js | 2 +- js/headings.js | 4 +- js/helpers.js | 2 +- js/location.js | 20 ++ js/logging.js | 11 +- js/models/adaptModel.js | 31 +-- js/models/articleModel.js | 11 +- js/models/blockModel.js | 11 +- js/models/componentModel.js | 12 +- js/models/configModel.js | 3 +- js/models/contentObjectModel.js | 7 +- js/models/courseModel.js | 17 +- js/models/menuModel.js | 7 +- js/models/pageModel.js | 7 +- js/models/questionModel.js | 3 +- js/mpabc.js | 17 +- js/notify.js | 15 +- js/offlineStorage.js | 12 +- js/reactHelpers.js | 4 +- js/router.js | 146 +++++----- js/scrolling.js | 28 +- js/startController.js | 32 ++- js/tracking.js | 18 +- js/views/adaptView.js | 14 +- js/views/articleView.js | 4 +- js/views/blockView.js | 4 +- js/views/buttonsView.js | 11 +- js/views/componentView.js | 6 +- js/views/contentObjectView.js | 8 +- js/views/drawerView.js | 18 +- js/views/navigationView.js | 14 +- js/views/notifyPopupView.js | 26 +- js/views/notifyView.js | 6 +- js/views/pageView.js | 4 +- js/views/questionView.js | 8 +- js/wait.js | 6 +- required/adapt/js/scriptLoader.js | 39 --- templates/header.jsx | 3 +- templates/image.jsx | 9 +- 55 files changed, 1125 insertions(+), 756 deletions(-) create mode 100644 js/components.js create mode 100644 js/deprecated.js create mode 100644 js/location.js diff --git a/js/a11y.js b/js/a11y.js index c48eb0ef..a8e8a719 100644 --- a/js/a11y.js +++ b/js/a11y.js @@ -1,4 +1,7 @@ import Adapt from 'core/js/adapt'; +import offlineStorage from 'core/js/offlineStorage'; +import device from 'core/js/device'; +import location from 'core/js/location'; import BrowserFocus from 'core/js/a11y/browserFocus'; import FocusOptions from 'core/js/a11y/focusOptions'; import KeyboardFocusOutline from 'core/js/a11y/keyboardFocusOutline'; @@ -6,9 +9,9 @@ import Log from 'core/js/a11y/log'; import Scroll from 'core/js/a11y/scroll'; import WrapFocus from 'core/js/a11y/wrapFocus'; import Popup from 'core/js/a11y/popup'; -import defaultAriaLevels from './enums/defaultAriaLevels'; - -import 'core/js/a11y/deprecated'; +import defaultAriaLevels from 'core/js/enums/defaultAriaLevels'; +import deprecated from 'core/js/a11y/deprecated'; +import logging from 'core/js/logging'; class A11y extends Backbone.Controller { @@ -70,12 +73,13 @@ class A11y extends Backbone.Controller { this._htmlCharRegex = /&.*;/g; /** @type {Object} */ this.config = null; - this._browserFocus = new BrowserFocus(); - this._keyboardFocusOutline = new KeyboardFocusOutline(); - this._wrapFocus = new WrapFocus(); - this._popup = new Popup(); - this._scroll = new Scroll(); - this.log = new Log(); + this._browserFocus = new BrowserFocus({ a11y: this }); + this._keyboardFocusOutline = new KeyboardFocusOutline({ a11y: this }); + this._wrapFocus = new WrapFocus({ a11y: this }); + this._popup = new Popup({ a11y: this }); + this._scroll = new Scroll({ a11y: this }); + this.log = new Log({ a11y: this }); + deprecated(this); this._removeLegacyElements(); this.listenToOnce(Adapt, { @@ -93,7 +97,7 @@ class A11y extends Backbone.Controller { this.config = Adapt.config.get('_accessibility'); this.config._isActive = false; this.config._options = _.defaults(this.config._options || {}, this.defaults()); - Adapt.offlineStorage.set('a11y', false); + offlineStorage.set('a11y', false); this.$html.toggleClass('has-accessibility', this.isEnabled()); this._setupNoSelect(); this._addFocuserDiv(); @@ -126,7 +130,7 @@ class A11y extends Backbone.Controller { if (!$legacyElements.length && !$navigationElements.length) { return; } - Adapt.log.warn('REMOVED: #accessibility-toggle and #accessibility-instructions have been removed. Please remove them from all of your .html files.'); + logging.warn('REMOVED: #accessibility-toggle and #accessibility-instructions have been removed. Please remove them from all of your .html files.'); $legacyElements.remove(); $navigationElements.remove(); } @@ -141,7 +145,7 @@ class A11y extends Backbone.Controller { _onNavigationEnd(view) { // Prevent sub-menu items provoking behaviour - if ((view?.model?.get('_id') !== Adapt.location._currentId) || !this.isEnabled()) { + if ((view?.model?.get('_id') !== location._currentId) || !this.isEnabled()) { return; } // Allow document to be read @@ -667,7 +671,7 @@ class A11y extends Backbone.Controller { // Drop focus errors as only happens when the element // isn't attached to the DOM. } - switch (Adapt.device.browser) { + switch (device.browser) { case 'internet explorer': case 'microsoft edge': case 'safari': @@ -792,4 +796,13 @@ class A11y extends Backbone.Controller { } -export default (Adapt.a11y = new A11y()); +const a11y = new A11y(); + +Object.defineProperty(Adapt, 'a11y', { + get() { + logging.deprecated('Adapt.a11y, please use core/js/a11y directly'); + return a11y; + } +}); + +export default a11y; diff --git a/js/a11y/browserFocus.js b/js/a11y/browserFocus.js index d21075a5..a506090c 100644 --- a/js/a11y/browserFocus.js +++ b/js/a11y/browserFocus.js @@ -6,7 +6,8 @@ import Adapt from 'core/js/adapt'; */ export default class BrowserFocus extends Backbone.Controller { - initialize() { + initialize({ a11y }) { + this.a11y = a11y; this._onBlur = this._onBlur.bind(this); this._onClick = this._onClick.bind(this); this.$body = $('body'); @@ -32,7 +33,7 @@ export default class BrowserFocus extends Backbone.Controller { * @param {JQuery.Event} event */ _onBlur(event) { - const config = Adapt.a11y.config; + const config = this.a11y.config; if (!config._isEnabled || !config._options._isFocusNextOnDisabled) { return; } @@ -50,7 +51,7 @@ export default class BrowserFocus extends Backbone.Controller { return; } // Move focus to next readable element - Adapt.a11y.focusNext($element); + this.a11y.focusNext($element); } /** @@ -68,7 +69,7 @@ export default class BrowserFocus extends Backbone.Controller { event.preventDefault(); event.stopImmediatePropagation(); } - const config = Adapt.a11y.config; + const config = this.a11y.config; if (!config._isEnabled || !config._options._isFocusOnClickEnabled) { return; } diff --git a/js/a11y/deprecated.js b/js/a11y/deprecated.js index 8e329334..c136e432 100644 --- a/js/a11y/deprecated.js +++ b/js/a11y/deprecated.js @@ -1,170 +1,171 @@ -import Adapt from 'core/js/adapt'; - -/** - * The old API is rerouted to the new API with warnings. - */ - -Object.assign($.fn, { - - isFixedPostion() { - Adapt.a11y.log.removed('$("..").isFixedPostion was unneeded and has been removed, let us know if you need it back.'); - return false; - }, - - a11y_aria_label() { - Adapt.a11y.log.removed('$("..").a11y_aria_label was incorrect behaviour.'); - return this; - }, - - limitedScrollTo() { - Adapt.a11y.log.removed('$.limitedScrollTo had no impact on the screen reader cursor.'); - return this; - }, - - a11y_text() { - Adapt.a11y.log.removed('a11y_text is no longer required. https://tink.uk/understanding-screen-reader-interaction-modes/'); - return this; - }, - - a11y_selected() { - Adapt.a11y.log.removed('$("..").a11y_selected is removed. Please use aria-live instead.'); - return this; - }, - - a11y_on(isOn) { - Adapt.a11y.log.deprecated('$("..").a11y_on, use Adapt.a11y.findTabbable($element); and Adapt.a11y.toggleAccessible($elements, isAccessible); instead.'); - const $tabbable = Adapt.a11y.findTabbable(this); - Adapt.a11y.toggleAccessible($tabbable, isOn); - return this; - }, - - a11y_only() { - Adapt.a11y.log.removed('$("..").a11y_only, use Adapt.a11y.popupOpened($popupElement); instead.'); - return this; - }, - - scrollDisable() { - if (Adapt.a11y.config._options._isScrollDisableEnabled === false) { +export default function(a11y) { + + /** + * The old API is rerouted to the new API with warnings. + */ + + Object.assign($.fn, { + + isFixedPostion() { + a11y.log.removed('$("..").isFixedPostion was unneeded and has been removed, let us know if you need it back.'); + return false; + }, + + a11y_aria_label() { + a11y.log.removed('$("..").a11y_aria_label was incorrect behaviour.'); return this; - } - Adapt.a11y.log.deprecated('$("..").scrollDisable, use Adapt.a11y.scrollDisable($elements); instead.'); - Adapt.a11y.scrollDisable(this); - return this; - }, + }, - scrollEnable() { - if (Adapt.a11y.config._options._isScrollDisableEnabled === false) { + limitedScrollTo() { + a11y.log.removed('$.limitedScrollTo had no impact on the screen reader cursor.'); + return this; + }, + + a11y_text() { + a11y.log.removed('a11y_text is no longer required. https://tink.uk/understanding-screen-reader-interaction-modes/'); + return this; + }, + + a11y_selected() { + a11y.log.removed('$("..").a11y_selected is removed. Please use aria-live instead.'); + return this; + }, + + a11y_on(isOn) { + a11y.log.deprecated('$("..").a11y_on, use a11y.findTabbable($element); and a11y.toggleAccessible($elements, isAccessible); instead.'); + const $tabbable = a11y.findTabbable(this); + a11y.toggleAccessible($tabbable, isOn); + return this; + }, + + a11y_only() { + a11y.log.removed('$("..").a11y_only, use a11y.popupOpened($popupElement); instead.'); + return this; + }, + + scrollDisable() { + if (a11y.config._options._isScrollDisableEnabled === false) { + return this; + } + a11y.log.deprecated('$("..").scrollDisable, use a11y.scrollDisable($elements); instead.'); + a11y.scrollDisable(this); + return this; + }, + + scrollEnable() { + if (a11y.config._options._isScrollDisableEnabled === false) { + return this; + } + a11y.log.deprecated('$("..").scrollEnable, use a11y.scrollEnable($elements); instead.'); + a11y.scrollEnable(this); + return this; + }, + + a11y_popup() { + a11y.log.deprecated('$("..").a11y_popup, use a11y.popupOpened($popupElement); instead.'); + return a11y.popupOpened(this); + }, + + a11y_cntrl(isOn, withDisabled) { + a11y.log.deprecated('$("..").a11y_cntrl, use a11y.toggleAccessible($elements, isAccessible); and if needed a11y.toggleEnabled($elements, isEnabled); instead.'); + a11y.toggleAccessible(this, isOn); + if (withDisabled) a11y.toggleEnabled(this, isOn); + return this; + }, + + a11y_cntrl_enabled(isOn) { + a11y.log.deprecated('$("..").a11y_cntrl_enabled, use a11y.toggleAccessibleEnabled($elements, isAccessibleEnabled); instead.'); + a11y.toggleAccessibleEnabled(this, isOn); + return this; + }, + + isReadable() { + a11y.log.deprecated('$("..").isReadable, use a11y.isReadable($element); instead.'); + return a11y.isReadable(this); + }, + + findForward(selector) { + a11y.log.removed('$("..").findForward has been removed as the use cases are very small, let us know if you need it back.'); + return a11y._findFirstForward(this, selector); + }, + + findWalk(selector) { + a11y.log.removed('$("..").findWalk has been removed as the use cases are very small, let us know if you need it back.'); + return a11y._findFindForwardDescendant(this, selector); + }, + + focusNoScroll() { + a11y.log.deprecated('$("..").focusNoScroll, use a11y.focus($element); instead.'); + return a11y.focus(this); + }, + + focusNext(returnOnly) { + a11y.log.deprecated('$("..").focusNext, use a11y.focusNext($element); or if needed a11y.findFirstReadable($element); instead.'); + if (returnOnly) { + return a11y.findFirstReadable(this); + } + return a11y.focusNext(this); + }, + + focusOrNext(returnOnly) { + a11y.log.deprecated('$("..").focusOrNext, use a11y.focusFirst($element); or if needed a11y.findFirstReadable($element); or a11y.isReadable($element); instead.'); + if (returnOnly) { + if (a11y.isReadable(this)) return this; + return a11y.findFirstReadable(this); + } + return a11y.focusFirst(this); + }, + + a11y_focus(dontDefer) { + a11y.log.deprecated('$("..").a11y_focus, use a11y.focusFirst($element, { defer: true }); instead.'); + a11y.focusFirst(this, { defer: !dontDefer }); return this; } - Adapt.a11y.log.deprecated('$("..").scrollEnable, use Adapt.a11y.scrollEnable($elements); instead.'); - Adapt.a11y.scrollEnable(this); - return this; - }, - - a11y_popup() { - Adapt.a11y.log.deprecated('$("..").a11y_popup, use Adapt.a11y.popupOpened($popupElement); instead.'); - return Adapt.a11y.popupOpened(this); - }, - - a11y_cntrl(isOn, withDisabled) { - Adapt.a11y.log.deprecated('$("..").a11y_cntrl, use Adapt.a11y.toggleAccessible($elements, isAccessible); and if needed Adapt.a11y.toggleEnabled($elements, isEnabled); instead.'); - Adapt.a11y.toggleAccessible(this, isOn); - if (withDisabled) Adapt.a11y.toggleEnabled(this, isOn); - return this; - }, - - a11y_cntrl_enabled(isOn) { - Adapt.a11y.log.deprecated('$("..").a11y_cntrl_enabled, use Adapt.a11y.toggleAccessibleEnabled($elements, isAccessibleEnabled); instead.'); - Adapt.a11y.toggleAccessibleEnabled(this, isOn); - return this; - }, - - isReadable() { - Adapt.a11y.log.deprecated('$("..").isReadable, use Adapt.a11y.isReadable($element); instead.'); - return Adapt.a11y.isReadable(this); - }, - - findForward(selector) { - Adapt.a11y.log.removed('$("..").findForward has been removed as the use cases are very small, let us know if you need it back.'); - return Adapt.a11y._findFirstForward(this, selector); - }, - - findWalk(selector) { - Adapt.a11y.log.removed('$("..").findWalk has been removed as the use cases are very small, let us know if you need it back.'); - return Adapt.a11y._findFindForwardDescendant(this, selector); - }, - - focusNoScroll() { - Adapt.a11y.log.deprecated('$("..").focusNoScroll, use Adapt.a11y.focus($element); instead.'); - return Adapt.a11y.focus(this); - }, - - focusNext(returnOnly) { - Adapt.a11y.log.deprecated('$("..").focusNext, use Adapt.a11y.focusNext($element); or if needed Adapt.a11y.findFirstReadable($element); instead.'); - if (returnOnly) { - return Adapt.a11y.findFirstReadable(this); - } - return Adapt.a11y.focusNext(this); - }, - - focusOrNext(returnOnly) { - Adapt.a11y.log.deprecated('$("..").focusOrNext, use Adapt.a11y.focusFirst($element); or if needed Adapt.a11y.findFirstReadable($element); or Adapt.a11y.isReadable($element); instead.'); - if (returnOnly) { - if (Adapt.a11y.isReadable(this)) return this; - return Adapt.a11y.findFirstReadable(this); + + }); + + Object.assign($, { + + a11y_alert() { + a11y.log.removed('$.a11y_alert is removed. Please use aria-live instead.'); + return this; + }, + + a11y_update() { + a11y.log.removed('a11y_update is no longer required.'); + return this; + }, + + a11y_text(text) { + a11y.log.removed('a11y_text is no longer required. https://tink.uk/understanding-screen-reader-interaction-modes/'); + return text; + }, + + a11y_on(isOn, selector) { + a11y.log.deprecated('$("..").a11y_on, use a11y.toggleHidden($elements, isHidden); instead.'); + return a11y.toggleHidden(selector, !isOn); + }, + + a11y_popdown($focusTarget) { + a11y.log.removed('$.a11y_popdown, use a11y.popupClosed($focusTarget); instead.'); + return a11y.popupClosed($focusTarget); + }, + + a11y_focus(dontDefer) { + a11y.log.deprecated('$.a11y_focus, use a11y.focusFirst("body", { defer: true }); instead.'); + a11y.focusFirst('body', { defer: !dontDefer }); + return this; + }, + + a11y_normalize(html) { + a11y.log.deprecated('$.a11y_normalize, use a11y.normalize("html"); instead.'); + return a11y.normalize(html); + }, + + a11y_remove_breaks(html) { + a11y.log.deprecated('$.a11y_remove_breaks, use a11y.removeBreaks("html"); instead.'); + return a11y.removeBreaks(html); } - return Adapt.a11y.focusFirst(this); - }, - - a11y_focus(dontDefer) { - Adapt.a11y.log.deprecated('$("..").a11y_focus, use Adapt.a11y.focusFirst($element, { defer: true }); instead.'); - Adapt.a11y.focusFirst(this, { defer: !dontDefer }); - return this; - } - -}); - -Object.assign($, { - - a11y_alert() { - Adapt.a11y.log.removed('$.a11y_alert is removed. Please use aria-live instead.'); - return this; - }, - - a11y_update() { - Adapt.a11y.log.removed('a11y_update is no longer required.'); - return this; - }, - - a11y_text(text) { - Adapt.a11y.log.removed('a11y_text is no longer required. https://tink.uk/understanding-screen-reader-interaction-modes/'); - return text; - }, - - a11y_on(isOn, selector) { - Adapt.a11y.log.deprecated('$("..").a11y_on, use Adapt.a11y.toggleHidden($elements, isHidden); instead.'); - return Adapt.a11y.toggleHidden(selector, !isOn); - }, - - a11y_popdown($focusTarget) { - Adapt.a11y.log.removed('$.a11y_popdown, use Adapt.a11y.popupClosed($focusTarget); instead.'); - return Adapt.a11y.popupClosed($focusTarget); - }, - - a11y_focus(dontDefer) { - Adapt.a11y.log.deprecated('$.a11y_focus, use Adapt.a11y.focusFirst("body", { defer: true }); instead.'); - Adapt.a11y.focusFirst('body', { defer: !dontDefer }); - return this; - }, - - a11y_normalize(html) { - Adapt.a11y.log.deprecated('$.a11y_normalize, use Adapt.a11y.normalize("html"); instead.'); - return Adapt.a11y.normalize(html); - }, - - a11y_remove_breaks(html) { - Adapt.a11y.log.deprecated('$.a11y_remove_breaks, use Adapt.a11y.removeBreaks("html"); instead.'); - return Adapt.a11y.removeBreaks(html); - } - -}); + + }); +} diff --git a/js/a11y/keyboardFocusOutline.js b/js/a11y/keyboardFocusOutline.js index 2f3888e2..2c188c39 100644 --- a/js/a11y/keyboardFocusOutline.js +++ b/js/a11y/keyboardFocusOutline.js @@ -7,7 +7,8 @@ import Adapt from 'core/js/adapt'; */ export default class KeyboardFocusOutline extends Backbone.Controller { - initialize() { + initialize({ a11y }) { + this.a11y = a11y; this._onKeyDown = this._onKeyDown.bind(this); this.$html = $('html'); this.showOnKeys = { @@ -33,7 +34,7 @@ export default class KeyboardFocusOutline extends Backbone.Controller { * Add styling classes if required. */ _start() { - const config = Adapt.a11y.config; + const config = this.a11y.config; if (config._options._isFocusOutlineDisabled) { this.$html.addClass('a11y-disable-focusoutline'); return; @@ -50,7 +51,7 @@ export default class KeyboardFocusOutline extends Backbone.Controller { * @param {JQuery.Event} event */ _onKeyDown(event) { - const config = Adapt.a11y.config; + const config = this.a11y.config; if (config._options._isFocusOutlineDisabled) { this.$html.addClass('a11y-disable-focusoutline'); return; diff --git a/js/a11y/log.js b/js/a11y/log.js index 66409898..11204d1c 100644 --- a/js/a11y/log.js +++ b/js/a11y/log.js @@ -1,4 +1,4 @@ -import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; /** * Controller for managing accessibilty logging, specifically used for @@ -6,12 +6,13 @@ import Adapt from 'core/js/adapt'; */ export default class Log extends Backbone.Controller { - initialize() { + initialize({ a11y }) { + this.a11y = a11y; this._warned = {}; } _hasWarned(args) { - const config = Adapt.a11y.config; + const config = this.a11y.config; if (!config._options._warnFirstOnly) { return false; } @@ -24,7 +25,7 @@ export default class Log extends Backbone.Controller { } _canWarn() { - const config = Adapt.a11y.config; + const config = this.a11y.config; return Boolean(config._options._warn); } @@ -36,7 +37,7 @@ export default class Log extends Backbone.Controller { if (this._hasWarned(args)) { return; } - Adapt.log.removed(...args); + logging.removed(...args); return this; } @@ -48,7 +49,7 @@ export default class Log extends Backbone.Controller { if (this._hasWarned(args)) { return; } - Adapt.log.deprecated(...args); + logging.deprecated(...args); return this; } diff --git a/js/a11y/popup.js b/js/a11y/popup.js index 10d23f9a..87ec491a 100644 --- a/js/a11y/popup.js +++ b/js/a11y/popup.js @@ -6,7 +6,8 @@ import Adapt from 'core/js/adapt'; */ export default class Popup extends Backbone.Controller { - initialize() { + initialize({ a11y }) { + this.a11y = a11y; /** * List of elements which form the base at which elements are generally tabbale * and aria-hidden='false'. @@ -42,14 +43,14 @@ export default class Popup extends Backbone.Controller { if (ignoreInternalTrigger) { return; } - Adapt.a11y.log.deprecated('Adapt.trigger("popup:opened", $element) is replaced with Adapt.a11y.popupOpened($element);'); + this.a11y.log.deprecated('Adapt.trigger("popup:opened", $element) is replaced with a11y.popupOpened($element);'); this.opened($element, true); }, 'popup:closed'($target, ignoreInternalTrigger) { if (ignoreInternalTrigger) { return; } - Adapt.a11y.log.deprecated('Adapt.trigger("popup:closed", $target) is replaced with Adapt.a11y.popupClosed($target);'); + this.a11y.log.deprecated('Adapt.trigger("popup:closed", $target) is replaced with a11y.popupClosed($target);'); this.closed($target, true); } }); @@ -60,7 +61,7 @@ export default class Popup extends Backbone.Controller { * restrict user interaction to the element specified. * * @param {Object} [$popupElement] Element encapulating the popup. - * @returns {Object} Returns `Adapt.a11y._popup`. + * @returns {Object} Returns `a11y._popup`. */ opened($popupElement, silent) { // Capture currently active element or element specified @@ -79,7 +80,7 @@ export default class Popup extends Backbone.Controller { */ _addPopupLayer($popupElement) { $popupElement = $($popupElement); - const config = Adapt.a11y.config; + const config = this.a11y.config; if (!config._isEnabled || !config._options._isPopupManagementEnabled || $popupElement.length === 0) { return $popupElement; } @@ -91,11 +92,10 @@ export default class Popup extends Backbone.Controller { $elements = $elements.add($siblings); $elements.each((index, item) => { const $item = $(item); - let elementUID; if (typeof item.a11y_uid === 'undefined') { item.a11y_uid = 'UID' + ++this._elementUIDIndex; } - elementUID = item.a11y_uid; + const elementUID = item.a11y_uid; if (this._tabIndexes[elementUID] === undefined) { this._tabIndexes[elementUID] = []; } @@ -132,7 +132,7 @@ export default class Popup extends Backbone.Controller { * attributes. * * @param {Object} [$focusElement] Element at which to move focus. - * @returns {Object} Returns `Adapt.a11y._popup`. + * @returns {Object} Returns `a11y._popup`. */ closed($focusElement, silent) { const $previousFocusElement = this._removeLastPopupLayer(); @@ -140,7 +140,7 @@ export default class Popup extends Backbone.Controller { if (!silent) { Adapt.trigger('popup:closed', $focusElement, true); } - Adapt.a11y.focusFirst($($focusElement), { preventScroll: true }); + this.a11y.focusFirst($($focusElement), { preventScroll: true }); return this; } @@ -151,7 +151,7 @@ export default class Popup extends Backbone.Controller { * @returns {Object} Returns previously active element. */ _removeLastPopupLayer() { - const config = Adapt.a11y.config; + const config = this.a11y.config; if (!config._isEnabled || !config._options._isPopupManagementEnabled) { return $(document.activeElement); } @@ -164,12 +164,11 @@ export default class Popup extends Backbone.Controller { const $item = $(item); let previousTabIndex = ''; let previousAriaHidden = ''; - let elementUID; if (typeof item.a11y_uid === 'undefined') { // assign element a unique id item.a11y_uid = 'UID' + ++this._elementUIDIndex; } - elementUID = item.a11y_uid; + const elementUID = item.a11y_uid; if (this._tabIndexes[elementUID]?.length) { // get previous tabindex if saved previousTabIndex = this._tabIndexes[elementUID].pop(); @@ -185,7 +184,7 @@ export default class Popup extends Backbone.Controller { $item.removeAttr('tabindex'); } else { $item.attr({ - 'tabindex': previousTabIndex + tabindex: previousTabIndex }); } } diff --git a/js/a11y/wrapFocus.js b/js/a11y/wrapFocus.js index 4ac110c0..b7ccbfcf 100644 --- a/js/a11y/wrapFocus.js +++ b/js/a11y/wrapFocus.js @@ -6,7 +6,8 @@ import Adapt from 'core/js/adapt'; */ export default class WrapFocus extends Backbone.Controller { - initialize() { + initialize({ a11y }) { + this.a11y = a11y; _.bindAll(this, '_onWrapAround'); this.listenTo(Adapt, { 'accessibility:ready': this._attachEventListeners @@ -14,7 +15,7 @@ export default class WrapFocus extends Backbone.Controller { } _attachEventListeners() { - const config = Adapt.a11y.config; + const config = this.a11y.config; $('body').on('click focus', config._options._focusguard, this._onWrapAround); } @@ -25,13 +26,13 @@ export default class WrapFocus extends Backbone.Controller { * @param {JQuery.Event} event */ _onWrapAround(event) { - const config = Adapt.a11y.config; + const config = this.a11y.config; if (!config._isEnabled || !config._options._isPopupWrapFocusEnabled) { return; } event.preventDefault(); event.stopPropagation(); - Adapt.a11y.focusFirst('body', { defer: false }); + this.a11y.focusFirst('body', { defer: false }); } } diff --git a/js/accessibility.js b/js/accessibility.js index 826de1d2..9a8fbf1c 100644 --- a/js/accessibility.js +++ b/js/accessibility.js @@ -2,13 +2,13 @@ import Adapt from 'core/js/adapt'; import a11y from 'core/js/a11y'; /** - * Backwards compatibility `Adapt.accessibility` reroutes to `Adapt.a11y` + * Backwards compatibility `Adapt.accessibility` reroutes to `a11y` * with a warning. */ Object.defineProperty(Adapt, 'accessibility', { get() { - a11y.log.deprecated('Adapt.accessibility has moved to Adapt.a11y'); + a11y.log.deprecated('Adapt.accessibility has moved to a11y'); return a11y; } diff --git a/js/adapt.js b/js/adapt.js index a80b0e3d..86e035f7 100644 --- a/js/adapt.js +++ b/js/adapt.js @@ -1,13 +1,10 @@ -import Wait from 'core/js/wait'; +import wait from 'core/js/wait'; import LockingModel from 'core/js/models/lockingModel'; class AdaptSingleton extends LockingModel { initialize() { this.loadScript = window.__loadScript; - this.location = {}; - this.store = {}; - this.setupWait(); } defaults() { @@ -26,26 +23,18 @@ class AdaptSingleton extends LockingModel { }; } - /** - * @deprecated since v6.0.0 - please use `Adapt.store` instead - */ - get componentStore() { - this.log.deprecated('Adapt.componentStore, please use Adapt.store instead'); - return this.store; - } - async init() { this.addDirection(); this.disableAnimation(); this.trigger('adapt:preInitialize'); - await this.wait.queue(); + await wait.queue(); // wait until no more completion checking this.deferUntilCompletionChecked(async () => { // start adapt in a full restored state this.trigger('adapt:start'); - await this.wait.queue(); + await wait.queue(); if (!Backbone.History.started) { Backbone.history.start(); @@ -54,7 +43,7 @@ class AdaptSingleton extends LockingModel { this.set('_isStarted', true); this.trigger('adapt:initialize'); - await this.wait.queue(); + await wait.queue(); }); } @@ -92,272 +81,19 @@ class AdaptSingleton extends LockingModel { }); } - setupWait() { - - this.wait = new Wait(); - - // Setup legacy events and handlers - const beginWait = () => { - this.log.deprecated('Use Adapt.wait.begin() as Adapt.trigger(\'plugin:beginWait\') may be removed in the future'); - this.wait.begin(); - }; - - const endWait = () => { - this.log.deprecated('Use Adapt.wait.end() as Adapt.trigger(\'plugin:endWait\') may be removed in the future'); - this.wait.end(); - }; - - const ready = () => { - if (this.wait.isWaiting()) { - return; - } - const isEventListening = (this._events['plugins:ready']); - if (!isEventListening) { - return; - } - this.log.deprecated("Use Adapt.wait.queue(callback) as Adapt.on('plugins:ready', callback) may be removed in the future"); - this.trigger('plugins:ready'); - }; - - this.listenTo(this.wait, 'ready', ready); - this.listenTo(this, { - 'plugin:beginWait': beginWait, - 'plugin:endWait': endWait - }); - - } - isWaitingForPlugins() { - this.log.deprecated('Use Adapt.wait.isWaiting() as Adapt.isWaitingForPlugins() may be removed in the future'); - return this.wait.isWaiting(); + this.log.deprecated('Use wait.isWaiting() as Adapt.isWaitingForPlugins() will be removed in the future'); + return wait.isWaiting(); } checkPluginsReady() { - this.log.deprecated('Use Adapt.wait.isWaiting() as Adapt.checkPluginsReady() may be removed in the future'); + this.log.deprecated('Use wait.isWaiting() as Adapt.checkPluginsReady() will be removed in the future'); if (this.isWaitingForPlugins()) { return; } this.trigger('plugins:ready'); } - /** - * Allows a selector to be passed in and Adapt will navigate to this element. Resolves - * asynchronously when the element has been navigated to. - * @param {string} selector CSS selector of the Adapt element you want to navigate to e.g. `".co-05"` - * @param {Object} [settings] The settings for the `$.scrollTo` function (See https://github.com/flesler/jquery.scrollTo#settings). - * @param {Object} [settings.replace=false] Set to `true` if you want to update the URL without creating an entry in the browser's history. - */ - async navigateToElement() {} - - /** - * Allows a selector to be passed in and Adapt will scroll to this element. Resolves - * asynchronously when the element has been navigated/scrolled to. - * @param {string} selector CSS selector of the Adapt element you want to navigate to e.g. `".co-05"` - * @param {Object} [settings={}] The settings for the `$.scrollTo` function (See https://github.com/flesler/jquery.scrollTo#settings). - * @param {Object} [settings.replace=false] Set to `true` if you want to update the URL without creating an entry in the browser's history. - */ - async scrollTo() {} - - /** - * Used to register models and views with `Adapt.store` - * @param {string|Array} name The name(s) of the model/view to be registered - * @param {object} object Object containing properties `model` and `view` or (legacy) an object representing the view - */ - register(name, object) { - if (Array.isArray(name)) { - // if an array is passed, iterate by recursive call - name.forEach(name => this.register(name, object)); - return object; - } - - if (name.split(' ').length > 1) { - // if name with spaces is passed, split and pass as array - this.register(name.split(' '), object); - return object; - } - - if ((!object.view && !object.model) || object instanceof Backbone.View) { - this.log.deprecated('View-only registrations are no longer supported'); - object = { view: object }; - } - - if (object.view && !object.view.template) { - object.view.template = name; - } - - const isModelSetAndInvalid = (object.model && - !(object.model.prototype instanceof Backbone.Model) && - !(object.model instanceof Function)); - if (isModelSetAndInvalid) { - throw new Error('The registered model is not a Backbone.Model or Function'); - } - - const isViewSetAndInvalid = (object.view && - !(object.view.prototype instanceof Backbone.View) && - !(object.view instanceof Function)); - if (isViewSetAndInvalid) { - throw new Error('The registered view is not a Backbone.View or Function'); - } - - this.store[name] = Object.assign({}, this.store[name], object); - - return object; - } - - /** - * Parses a view class name. - * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data - */ - getViewName(nameModelViewOrData) { - if (typeof nameModelViewOrData === 'string') { - return nameModelViewOrData; - } - if (nameModelViewOrData instanceof Backbone.Model) { - nameModelViewOrData = nameModelViewOrData.toJSON(); - } - if (nameModelViewOrData instanceof Backbone.View) { - let foundName; - Object.entries(this.store).forEach(([key, entry]) => { - if (!entry?.view) return; - if (!(nameModelViewOrData instanceof entry.view)) return; - foundName = key; - return true; - }); - return foundName; - } - if (nameModelViewOrData instanceof Object) { - const names = [ - typeof nameModelViewOrData._view === 'string' && nameModelViewOrData._view, - typeof nameModelViewOrData._component === 'string' && nameModelViewOrData._component, - typeof nameModelViewOrData._type === 'string' && nameModelViewOrData._type - ].filter(Boolean); - if (names.length) { - // find first fitting view name - const name = names.find(name => this.store[name]?.view); - return name || names.pop(); // return last available if none found - } - } - throw new Error('Cannot derive view class name from input'); - } - - /** - * Fetches a view class from the store. For a usage example, see either HotGraphic or Narrative - * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data - * @returns {Backbone.View} Reference to the view class - */ - getViewClass(nameModelViewOrData) { - const name = this.getViewName(nameModelViewOrData); - const object = this.store[name]; - if (!object) { - this.log.warnOnce(`A view for '${name}' isn't registered in your project`); - return; - } - const isBackboneView = (object.view?.prototype instanceof Backbone.View); - if (!isBackboneView && object.view instanceof Function) { - return object.view(); - } - return object.view; - } - - /** - * Parses a model class name. - * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"`, the model to process or its json data - */ - getModelName(nameModelOrData) { - if (typeof nameModelOrData === 'string') { - return nameModelOrData; - } - if (nameModelOrData instanceof Backbone.Model) { - nameModelOrData = nameModelOrData.toJSON(); - } - if (nameModelOrData instanceof Object) { - const name = nameModelOrData._component; - const entry = this.store[name]; - const isViewOnlyQuestion = entry && !entry.model && entry.view?._isQuestionType; - if (isViewOnlyQuestion) { - // Use question model by default - this.log.deprecated(`Assuming a question model for a view-only question: ${name}`); - return 'question'; - } - const names = [ - typeof nameModelOrData._model === 'string' && nameModelOrData._model, - typeof nameModelOrData._component === 'string' && nameModelOrData._component, - typeof nameModelOrData._type === 'string' && nameModelOrData._type - ].filter(Boolean); - if (names.length) { - // find first fitting model name - const name = names.find(name => this.store[name]?.model); - return name || names.pop(); // return last available if none found - } - } - throw new Error('Cannot derive model class name from input'); - } - - /** - * Fetches a model class from the store. For a usage example, see either HotGraphic or Narrative - * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"` or its json data - * @returns {Backbone.Model} Reference to the view class - */ - getModelClass(nameModelOrData) { - const name = this.getModelName(nameModelOrData); - const object = this.store[name]; - if (!object) { - this.log.warnOnce(`A model for '${name}' isn't registered in your project`); - return; - } - const isBackboneModel = (object.model?.prototype instanceof Backbone.Model); - if (!isBackboneModel && object.model instanceof Function) { - return object.model(); - } - return object.model; - } - - /** - * Looks up a model by its `_id` property - * @param {string} id The id of the item e.g. "co-05" - * @return {Backbone.Model} - */ - findById(id) { - return this.data.findById(id); - } - - findViewByModelId(id) { - const model = this.data.findById(id); - if (!model) return; - - if (model === this.parentView.model) return this.parentView; - - const idPathToView = [id]; - const currentLocationId = this.location._currentId; - const currentLocationModel = model.getAncestorModels().find(model => { - const modelId = model.get('_id'); - if (modelId === currentLocationId) return true; - idPathToView.unshift(modelId); - return false; - }); - - if (!currentLocationModel) { - return console.warn(`Adapt.findViewByModelId() unable to find view for model id: ${id}`); - } - - const foundView = idPathToView.reduce((view, currentId) => { - if (!view) return null; - const childViews = view.getChildViews(); - return childViews?.find(view => view.model.get('_id') === currentId); - }, this.parentView); - - return foundView; - } - - /** - * Returns the model represented by the trackingPosition. - * @param {Array} trackingPosition Represents the relative location of a model to a _trackingId - * @returns {Backbone.Model} - */ - findByTrackingPosition(trackingPosition) { - return this.data.findByTrackingPosition(trackingPosition); - } - /** * Relative strings describe the number and type of hops in the model hierarchy * @param {string} relativeString "@component +1" means to move one component forward from the current model @@ -414,7 +150,7 @@ class AdaptSingleton extends LockingModel { }); } this.trigger('preRemove', currentView); - await this.wait.queue(); + await wait.queue(); // Facilitate contentObject transitions if (currentView && this.get('_shouldDestroyContentObjects')) { currentView.destroy(); @@ -423,6 +159,150 @@ class AdaptSingleton extends LockingModel { _.defer(this.trigger.bind(this), 'postRemove', currentView); } + /** + * @deprecated Please use core/js/a11y instead + */ + get a11y() {} + + /** + * @deprecated Please use core/js/components instead + */ + get componentStore() {} + + /** + * @deprecated Please use core/js/data instead + */ + get data() {} + + /** + * @deprecated Please use core/js/device instead + */ + get device() {} + + /** + * @deprecated Please use core/js/drawer instead + */ + get drawer() {} + + /** + * @deprecated Please use core/js/location instead + */ + get location() {} + + /** + * @deprecated Please use core/js/notify instead + */ + get notify() {} + + /** + * @deprecated Please use core/js/offlineStorage instead + */ + get offlineStorage() {} + + /** + * @deprecated Please use core/js/router instead + */ + get router() {} + + /** + * @deprecated Please use core/js/scrolling instead + */ + get scrolling() {} + + /** + * @deprecated Please use core/js/components instead + */ + get store() {} + + /** + * @deprecated Please use core/js/wait instead + */ + get wait() {} + + /** + * Allows a selector to be passed in and Adapt will navigate to this element. Resolves + * asynchronously when the element has been navigated to. /** + * @deprecated Please use router.navigateToElement instead. + * @param {string} selector CSS selector of the Adapt element you want to navigate to e.g. `".co-05"` + * @param {Object} [settings] The settings for the `$.scrollTo` function (See https://github.com/flesler/jquery.scrollTo#settings). + * @param {Object} [settings.replace=false] Set to `true` if you want to update the URL without creating an entry in the browser's history. + */ + async navigateToElement() {} + + /** + * Allows a selector to be passed in and Adapt will scroll to this element. Resolves + * asynchronously when the element has been navigated/scrolled to. + * @deprecated Please use router.navigateToElement instead. + * @param {string} selector CSS selector of the Adapt element you want to navigate to e.g. `".co-05"` + * @param {Object} [settings={}] The settings for the `$.scrollTo` function (See https://github.com/flesler/jquery.scrollTo#settings). + * @param {Object} [settings.replace=false] Set to `true` if you want to update the URL without creating an entry in the browser's history. + */ + async scrollTo() {} + + /** + * Used to register models and views with `store` + * @deprecated Please use store.register instead. + * @param {string|Array} name The name(s) of the model/view to be registered + * @param {object} object Object containing properties `model` and `view` or (legacy) an object representing the view + */ + register(name, object) {} + + /** + * Parses a view class name. + * @deprecated Please use store.getViewName instead. + * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data + */ + getViewName() {} + + /** + * Fetches a view class from the store. For a usage example, see either HotGraphic or Narrative + * @deprecated Please use store.getViewClass instead. + * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data + * @returns {Backbone.View} Reference to the view class + */ + getViewClass() {} + + /** + * Parses a model class name. + * @deprecated Please use store.getModelName instead. + * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"`, the model to process or its json data + */ + getModelName() {} + + /** + * Fetches a model class from the store. For a usage example, see either HotGraphic or Narrative + * @deprecated Please use store.getModelClass instead. + * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"` or its json data + * @returns {Backbone.Model} Reference to the view class + */ + getModelClass() {} + + /** + * Looks up a model by its `_id` property + * @deprecated Please use data.findById instead. + * @param {string} id The id of the item e.g. "co-05" + * @return {Backbone.Model} + */ + findById() {} + + /** + * Looks up a view by its model `_id` property + * @deprecated Please use data.findViewByModelId instead. + * @param {string} id The id of the item e.g. "co-05" + * @return {Backbone.View} + */ + findViewByModelId() {} + + /** + * Returns the model represented by the trackingPosition. + * @deprecated Please use data.findByTrackingPosition instead. + * @param {Array} trackingPosition Represents the relative location of a model to a _trackingId + * @returns {Backbone.Model} + */ + findByTrackingPosition() {} + } -export default new AdaptSingleton(); +const Adapt = new AdaptSingleton(); + +export default Adapt; diff --git a/js/app.js b/js/app.js index 051f6bb4..a9da3241 100644 --- a/js/app.js +++ b/js/app.js @@ -1,10 +1,14 @@ import Adapt from 'core/js/adapt'; +import 'core/js/wait'; +import 'core/js/deprecated.js'; +import 'core/js/components'; +import 'core/js/location'; import 'core/js/templates'; import 'core/js/fixes'; import 'core/js/accessibility'; -import 'core/js/data'; +import data from 'core/js/data'; import 'core/js/offlineStorage'; -import 'core/js/logging'; +import logging from 'core/js/logging'; import 'core/js/tracking'; import 'core/js/device'; import 'core/js/drawer'; @@ -16,14 +20,13 @@ import 'core/js/helpers'; import 'core/js/scrolling'; import 'core/js/headings'; import 'core/js/navigation'; +import 'core/js/startController'; import 'plugins'; $('body').append(Handlebars.templates.loading()); -Adapt.data.on('ready', function triggerInit() { - Adapt.log.debug('Calling Adapt.init'); - +data.on('ready', () => { + logging.debug('Calling Adapt.init'); Adapt.init(); - Adapt.off('adaptCollection:dataLoaded courseModel:dataLoaded'); }).init(); diff --git a/js/childEvent.js b/js/childEvent.js index b0683eb2..78ca88a7 100644 --- a/js/childEvent.js +++ b/js/childEvent.js @@ -1,4 +1,4 @@ -import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; /** * Event object triggered for controlling child view rendering. @@ -44,11 +44,11 @@ export default class ChildEvent extends Backbone.Controller { */ set model(model) { if (this.type !== 'requestChild') { - Adapt.log.warn(`Cannot change model in ${this.type} event.`); + logging.warn(`Cannot change model in ${this.type} event.`); return; } if (this._model) { - Adapt.log.warn(`Cannot inject two models in one sitting. ${model.get('_id')} attempts to overwrite ${this._model.get('_id')}`); + logging.warn(`Cannot inject two models in one sitting. ${model.get('_id')} attempts to overwrite ${this._model.get('_id')}`); return; } this._model = model; diff --git a/js/components.js b/js/components.js new file mode 100644 index 00000000..904ddd3d --- /dev/null +++ b/js/components.js @@ -0,0 +1,221 @@ +import Backbone from 'backbone'; +import logging from 'core/js/logging'; +import Adapt from 'core/js/adapt'; + +class Components extends Backbone.Controller { + + initialize() { + this._register = {}; + } + + /** + * Used to register models and views with `Adapt.store` + * @param {string|Array} name The name(s) of the model/view to be registered + * @param {object} object Object containing properties `model` and `view` or (legacy) an object representing the view + */ + register(name, object) { + if (Array.isArray(name)) { + // if an array is passed, iterate by recursive call + name.forEach(name => this.register(name, object)); + return object; + } + + if (name.split(' ').length > 1) { + // if name with spaces is passed, split and pass as array + this.register(name.split(' '), object); + return object; + } + + if ((!object.view && !object.model) || object instanceof Backbone.View) { + logging.deprecated('View-only registrations are no longer supported'); + object = { view: object }; + } + + if (object.view && !object.view.template) { + object.view.template = name; + } + + const isModelSetAndInvalid = (object.model && + !(object.model.prototype instanceof Backbone.Model) && + !(object.model instanceof Function)); + if (isModelSetAndInvalid) { + throw new Error('The registered model is not a Backbone.Model or Function'); + } + + const isViewSetAndInvalid = (object.view && + !(object.view.prototype instanceof Backbone.View) && + !(object.view instanceof Function)); + if (isViewSetAndInvalid) { + throw new Error('The registered view is not a Backbone.View or Function'); + } + + this._register[name] = Object.assign({}, this._register[name], object); + + return object; + } + + /** + * Parses a view class name. + * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data + */ + getViewName(nameModelViewOrData) { + if (typeof nameModelViewOrData === 'string') { + return nameModelViewOrData; + } + if (nameModelViewOrData instanceof Backbone.Model) { + nameModelViewOrData = nameModelViewOrData.toJSON(); + } + if (nameModelViewOrData instanceof Backbone.View) { + let foundName; + Object.entries(this._register).forEach(([key, entry]) => { + if (!entry?.view) return; + if (!(nameModelViewOrData instanceof entry.view)) return; + foundName = key; + return true; + }); + return foundName; + } + if (nameModelViewOrData instanceof Object) { + const names = [ + typeof nameModelViewOrData._view === 'string' && nameModelViewOrData._view, + typeof nameModelViewOrData._component === 'string' && nameModelViewOrData._component, + typeof nameModelViewOrData._type === 'string' && nameModelViewOrData._type + ].filter(Boolean); + if (names.length) { + // find first fitting view name + const name = names.find(name => this._register[name]?.view); + return name || names.pop(); // return last available if none found + } + } + throw new Error('Cannot derive view class name from input'); + } + + /** + * Fetches a view class from the components. For a usage example, see either HotGraphic or Narrative + * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data + * @returns {Backbone.View} Reference to the view class + */ + getViewClass(nameModelViewOrData) { + const name = this.getViewName(nameModelViewOrData); + const object = this._register[name]; + if (!object) { + logging.warnOnce(`A view for '${name}' isn't registered in your project`); + return; + } + const isBackboneView = (object.view?.prototype instanceof Backbone.View); + if (!isBackboneView && object.view instanceof Function) { + return object.view(); + } + return object.view; + } + + /** + * Parses a model class name. + * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"`, the model to process or its json data + */ + getModelName(nameModelOrData) { + if (typeof nameModelOrData === 'string') { + return nameModelOrData; + } + if (nameModelOrData instanceof Backbone.Model) { + nameModelOrData = nameModelOrData.toJSON(); + } + if (nameModelOrData instanceof Object) { + const name = nameModelOrData._component; + const entry = this._register[name]; + const isViewOnlyQuestion = entry && !entry.model && entry.view?._isQuestionType; + if (isViewOnlyQuestion) { + // Use question model by default + logging.deprecated(`Assuming a question model for a view-only question: ${name}`); + return 'question'; + } + const names = [ + typeof nameModelOrData._model === 'string' && nameModelOrData._model, + typeof nameModelOrData._component === 'string' && nameModelOrData._component, + typeof nameModelOrData._type === 'string' && nameModelOrData._type + ].filter(Boolean); + if (names.length) { + // find first fitting model name + const name = names.find(name => this._register[name]?.model); + return name || names.pop(); // return last available if none found + } + } + throw new Error('Cannot derive model class name from input'); + } + + /** + * Fetches a model class from the components. For a usage example, see either HotGraphic or Narrative + * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"` or its json data + * @returns {Backbone.Model} Reference to the view class + */ + getModelClass(nameModelOrData) { + const name = this.getModelName(nameModelOrData); + const object = this._register[name]; + if (!object) { + logging.warnOnce(`A model for '${name}' isn't registered in your project`); + return; + } + const isBackboneModel = (object.model?.prototype instanceof Backbone.Model); + if (!isBackboneModel && object.model instanceof Function) { + return object.model(); + } + return object.model; + } + +} + +const components = new Components(); +components.register = components.register.bind(components); +components.getViewName = components.getViewName.bind(components); +components.getViewClass = components.getViewClass.bind(components); +components.getModelName = components.getModelName.bind(components); +components.getModelClass = components.getModelClass.bind(components); + +Object.defineProperties(Adapt, { + store: { + get() { + logging.deprecated('Adapt.store, please use core/js/components directly'); + return components._register; + } + }, + componentStore: { + get() { + logging.deprecated('Adapt.componentStore, please use core/js/components directly'); + return components._register; + } + }, + register: { + get() { + logging.deprecated('components.register, please use components.register instead'); + return components.register; + } + }, + getViewName: { + get() { + logging.deprecated('Adapt.getViewName, please use components.getViewName instead'); + return components.getViewName; + } + + }, + getViewClass: { + get() { + logging.deprecated('Adapt.getViewClass, please use components.getViewClass instead'); + return components.getViewClass; + } + + }, + getModelName: { + get() { + logging.deprecated('Adapt.getModelName, please use components.getModelName instead'); + return components.getModelName; + } + }, + getModelClass: { + get() { + logging.deprecated('Adapt.getModelClass, please use components.getModelClass instead'); + return components.getModelClass; + } + } +}); + +export default components; diff --git a/js/data.js b/js/data.js index 5b3f0d9c..b8b5a7ad 100644 --- a/js/data.js +++ b/js/data.js @@ -1,16 +1,18 @@ import Adapt from 'core/js/adapt'; +import offlineStorage from 'core/js/offlineStorage'; +import wait from 'core/js/wait'; +import components from 'core/js/components'; import AdaptCollection from 'core/js/collections/adaptCollection'; import BuildModel from 'core/js/models/buildModel'; import ConfigModel from 'core/js/models/configModel'; import LockingModel from 'core/js/models/lockingModel'; - -import 'core/js/models/courseModel'; -import 'core/js/startController'; +import logging from 'core/js/logging'; +import location from 'core/js/location'; class Data extends AdaptCollection { model(json) { - const ModelClass = Adapt.getModelClass(json); + const ModelClass = components.getModelClass(json); if (!ModelClass) { return new LockingModel(json); } @@ -72,7 +74,7 @@ class Data extends AdaptCollection { } onLanguageChange(model, language) { - Adapt.offlineStorage.set('lang', language); + offlineStorage.set('lang', language); // set `_isStarted` back to `false` when changing language so that the learner's answers // to questions get restored in the new language when `_restoreStateOnLanguageChange: true` // see https://github.com/adaptlearning/adapt_framework/issues/2977 @@ -117,7 +119,7 @@ class Data extends AdaptCollection { manifest = await this.getJSON(manifestPath); } catch (err) { manifest = ['course.json', 'contentObjects.json', 'articles.json', 'blocks.json', 'components.json']; - Adapt.log.warnOnce(`Manifest path '${manifestPath} not found. Using traditional files: ${manifest.join(', ')}`); + logging.warnOnce(`Manifest path '${manifestPath} not found. Using traditional files: ${manifest.join(', ')}`); } const allFileData = await Promise.all(manifest.map(filePath => { return this.getJSON(`${languagePath}${filePath}`); @@ -129,7 +131,7 @@ class Data extends AdaptCollection { } else if (fileData instanceof Object) { result.push(fileData); } else { - Adapt.log.warnOnce(`File data isn't an array or object: ${fileData.__path__}`); + logging.warnOnce(`File data isn't an array or object: ${fileData.__path__}`); } return result; }, []); @@ -150,39 +152,33 @@ class Data extends AdaptCollection { }); this.trigger('reset'); this.trigger('loaded'); - await Adapt.wait.queue(); + await wait.queue(); } async triggerDataLoaded() { - Adapt.log.debug('Firing app:dataLoaded'); + logging.debug('Firing app:dataLoaded'); try { // Setup the newly added models this.forEach(model => model.setupModel?.()); Adapt.trigger('app:dataLoaded'); } catch (e) { - Adapt.log.error('Error during app:dataLoading trigger', e); + logging.error('Error during app:dataLoading trigger', e); } - await Adapt.wait.queue(); + await wait.queue(); } async triggerDataReady(newLanguage) { if (newLanguage) { Adapt.trigger('app:languageChanged', newLanguage); - this.performStartController(); + await wait.queue(); } - Adapt.log.debug('Firing app:dataReady'); + logging.debug('Firing app:dataReady'); try { Adapt.trigger('app:dataReady'); } catch (e) { - Adapt.log.error('Error during app:dataReady trigger', e); + logging.error('Error during app:dataReady trigger', e); } - await Adapt.wait.queue(); - } - - performStartController() { - Adapt.startController.loadCourseData(); - const hash = Adapt.startController.isEnabled() ? Adapt.startController.getStartHash(false) : '#/'; - Adapt.router.navigate(hash, { trigger: true, replace: true }); + await wait.queue(); } triggerInit() { @@ -205,12 +201,45 @@ class Data extends AdaptCollection { findById(id) { const model = this._byAdaptID[id]; if (!model) { - console.warn(`Adapt.findById() unable to find id: ${id}`); + console.warn(`data.findById() unable to find id: ${id}`); return; } return model; } + /** + * Looks up a view by its model `_id` property + * @param {string} id The id of the item e.g. "co-05" + * @return {Backbone.View} + */ + findViewByModelId(id) { + const model = this.findById(id); + if (!model) return; + + if (model === Adapt.parentView.model) return Adapt.parentView; + + const idPathToView = [id]; + const currentLocationId = location._currentId; + const currentLocationModel = model.getAncestorModels().find(model => { + const modelId = model.get('_id'); + if (modelId === currentLocationId) return true; + idPathToView.unshift(modelId); + return false; + }); + + if (!currentLocationModel) { + return console.warn(`data.findViewByModelId() unable to find view for model id: ${id}`); + } + + const foundView = idPathToView.reduce((view, currentId) => { + if (!view) return null; + const childViews = view.getChildViews(); + return childViews?.find(view => view.model.get('_id') === currentId); + }, Adapt.parentView); + + return foundView; + } + /** * Returns the model represented by the trackingPosition. * @param {Array} trackingPosition Represents the relative location of a model to a _trackingId @@ -220,7 +249,7 @@ class Data extends AdaptCollection { const [ trackingId, indexInTrackingIdDescendants ] = trackingPosition; const trackingIdModel = this.find(model => model.get('_trackingId') === trackingId); if (!trackingIdModel) { - console.warn(`Adapt.findByTrackingPosition() unable to find trackingPosition: ${trackingPosition}`); + console.warn(`data.findByTrackingPosition() unable to find trackingPosition: ${trackingPosition}`); return; } if (indexInTrackingIdDescendants >= 0) { @@ -236,4 +265,37 @@ class Data extends AdaptCollection { } -export default (Adapt.data = new Data()); +const data = new Data(); + +data.findById = data.findById.bind(data); +data.findViewByModelId = data.findViewByModelId.bind(data); +data.findByTrackingPosition = data.findByTrackingPosition.bind(data); + +Object.defineProperties(Adapt, { + data: { + get() { + logging.deprecated('Adapt.data, please use core/js/data directly'); + return data; + } + }, + findById: { + get() { + logging.deprecated('Adapt.findById, please use data.findById directly'); + return data.findById; + } + }, + findViewByModelId: { + get() { + logging.deprecated('Adapt.findViewByModelId, data.findViewByModelId directly'); + return data.findViewByModelId; + } + }, + findByTrackingPosition: { + get() { + logging.deprecated('Adapt.findByTrackingPosition, please use data.findByTrackingPosition directly'); + return data.findByTrackingPosition; + } + } +}); + +export default data; diff --git a/js/deprecated.js b/js/deprecated.js new file mode 100644 index 00000000..9965308f --- /dev/null +++ b/js/deprecated.js @@ -0,0 +1,42 @@ +import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; +import wait from 'core/js/wait'; + +/** START REDUNDANT ADAPT WAIT BEHAVIOUR */ +Object.defineProperties(Adapt, { + wait: { + get() { + logging.deprecated('Adapt.wait, please use src/core/wait instead'); + return wait; + } + } +}); + +const beginWait = () => { + logging.deprecated('Use wait.begin() as Adapt.trigger(\'plugin:beginWait\') will be removed in the future'); + wait.begin(); +}; + +const endWait = () => { + logging.deprecated('Use wait.end() as Adapt.trigger(\'plugin:endWait\') will be removed in the future'); + wait.end(); +}; + +const ready = () => { + if (wait.isWaiting()) { + return; + } + const isEventListening = (Adapt._events['plugins:ready']); + if (!isEventListening) { + return; + } + logging.deprecated("Use wait.queue(callback) as Adapt.on('plugins:ready', callback) will be removed in the future"); + Adapt.trigger('plugins:ready'); +}; + +Adapt.listenTo(wait, 'ready', ready); +Adapt.on({ + 'plugin:beginWait': beginWait, + 'plugin:endWait': endWait +}); +/** END REDUNDANT ADAPT WAIT BEHAVIOUR */ diff --git a/js/device.js b/js/device.js index 968e8606..77a1ce46 100644 --- a/js/device.js +++ b/js/device.js @@ -1,5 +1,6 @@ import Adapt from 'core/js/adapt'; import Bowser from 'bowser'; +import logging from 'core/js/logging'; class Device extends Backbone.Controller { @@ -190,4 +191,13 @@ class Device extends Backbone.Controller { } -export default (Adapt.device = new Device()); +const device = new Device(); + +Object.defineProperty(Adapt, 'device', { + get() { + logging.deprecated('device, please use core/js/device directly'); + return device; + } +}); + +export default device; diff --git a/js/drawer.js b/js/drawer.js index ccfc7344..b38ca461 100644 --- a/js/drawer.js +++ b/js/drawer.js @@ -1,5 +1,6 @@ import Adapt from 'core/js/adapt'; import DrawerView from 'core/js/views/drawerView'; +import logging from 'core/js/logging'; const DrawerCollection = new Backbone.Collection(null, { comparator: 'drawerOrder' }); const Drawer = {}; @@ -25,4 +26,11 @@ Adapt.on({ } }); -export default (Adapt.drawer = Drawer); +Object.defineProperty(Adapt, 'drawer', { + get() { + logging.deprecated('Adapt.drawer, please use core/js/drawer directly'); + return Drawer; + } +}); + +export default Drawer; diff --git a/js/fixes/reactHelpers.html.js b/js/fixes/reactHelpers.html.js index 527503f0..e99fcb86 100644 --- a/js/fixes/reactHelpers.html.js +++ b/js/fixes/reactHelpers.html.js @@ -1,7 +1,7 @@ import Adapt from 'core/js/adapt'; import HTMLReactParser from 'html-react-parser'; import 'core/js/templates'; -import logging from '../logging'; +import logging from 'core/js/logging'; /** * 27 October 2021 https://github.com/adaptlearning/adapt_authoring/issues/2570 diff --git a/js/headings.js b/js/headings.js index 68716f76..addd8bf7 100644 --- a/js/headings.js +++ b/js/headings.js @@ -1,5 +1,5 @@ -import Adapt from './adapt'; -import HeadingView from './views/headingView'; +import Adapt from 'core/js/adapt'; +import HeadingView from 'core/js/views/headingView'; class Headings extends Backbone.Controller { diff --git a/js/helpers.js b/js/helpers.js index b20e851d..f69217fe 100644 --- a/js/helpers.js +++ b/js/helpers.js @@ -1,5 +1,5 @@ import Adapt from 'core/js/adapt'; -import a11y from './a11y'; +import a11y from 'core/js/a11y'; const helpers = { diff --git a/js/location.js b/js/location.js new file mode 100644 index 00000000..31926861 --- /dev/null +++ b/js/location.js @@ -0,0 +1,20 @@ +import Backbone from 'backbone'; +import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; + +class Location extends Backbone.Controller { + +} + +const location = new Location(); + +Object.defineProperties(Adapt, { + location: { + get() { + logging.deprecated('Adapt.location, please use core/js/location directly'); + return location; + } + } +}); + +export default location; diff --git a/js/logging.js b/js/logging.js index 0f93a545..3236424a 100644 --- a/js/logging.js +++ b/js/logging.js @@ -133,4 +133,13 @@ class Logging extends Backbone.Controller { } -export default (Adapt.log = new Logging()); +const logging = new Logging(); + +Object.defineProperty(Adapt, 'log', { + get() { + logging.deprecated('logging, please use core/js/logging directly'); + return logging; + } +}); + +export default logging; diff --git a/js/models/adaptModel.js b/js/models/adaptModel.js index ec667ffc..9f1e0cb6 100644 --- a/js/models/adaptModel.js +++ b/js/models/adaptModel.js @@ -1,7 +1,8 @@ import Adapt from 'core/js/adapt'; +import data from 'core/js/data'; import ModelEvent from 'core/js/modelEvent'; import LockingModel from 'core/js/models/lockingModel'; -import 'core/js/logging'; +import logging from 'core/js/logging'; export default class AdaptModel extends LockingModel { @@ -19,7 +20,7 @@ export default class AdaptModel extends LockingModel { switch (name) { case '_parent': case '_children': - Adapt.log.deprecated('Use model.getChildren() or model.getParent() instead of model.get(\'_children\') or model.get(\'_parent\')'); + logging.deprecated('Use model.getChildren() or model.getParent() instead of model.get(\'_children\') or model.get(\'_parent\')'); } return super.get(name); } @@ -344,7 +345,7 @@ export default class AdaptModel extends LockingModel { const singular = isPluralized && lowerCased.slice(0, -1); // remove pluralization if ending in s const singularLowerCased = (singular || lowerCased).toLowerCase(); if (isPluralized || hasUpperCase) { - Adapt.log.deprecated(`'${typeGroup}' appears pluralized or contains uppercase characters, suggest using the singular, lowercase type group '${singularLowerCased}'.`); + logging.deprecated(`'${typeGroup}' appears pluralized or contains uppercase characters, suggest using the singular, lowercase type group '${singularLowerCased}'.`); } const pluralizedLowerCaseTypes = [ singularLowerCased, @@ -491,7 +492,7 @@ export default class AdaptModel extends LockingModel { findRelativeModel(relativeString, options = {}) { // return a model relative to the specified one if opinionated const rootModel = options.limitParentId ? - Adapt.findById(options.limitParentId) : + data.findById(options.limitParentId) : Adapt.course; const relativeDescriptor = Adapt.parseRelativeString(relativeString); @@ -555,7 +556,7 @@ export default class AdaptModel extends LockingModel { break; } if (movementCount === moveBy) { - return Adapt.findById(descendant.get('_id')); + return data.findById(descendant.get('_id')); } movementCount++; } @@ -577,8 +578,8 @@ export default class AdaptModel extends LockingModel { childrenCollection = new Backbone.Collection(); } else { const id = this.get('_id'); - // Look up child by _parentId from Adapt.data - const children = Adapt.data.filter(model => model.get('_parentId') === id); + // Look up child by _parentId from data + const children = data.filter(model => model.get('_parentId') === id); childrenCollection = new Backbone.Collection(children); } @@ -614,8 +615,8 @@ export default class AdaptModel extends LockingModel { } const parentId = this.get('_parentId'); if (!parentId) return; - // Look up parent by id from Adapt.data - this.setParent(Adapt.findById(parentId)); + // Look up parent by id from data + this.setParent(data.findById(parentId)); return this._parentModel; } @@ -649,7 +650,7 @@ export default class AdaptModel extends LockingModel { if (this._hasSiblingsAndSelf === false) { return this.get('_siblings'); } - siblings = Adapt.data.filter(model => { + siblings = data.filter(model => { return model.get('_parentId') === parentId && model.get('_id') !== id; }); @@ -662,7 +663,7 @@ export default class AdaptModel extends LockingModel { return this.get('_siblings'); } - siblings = Adapt.data.filter(model => { + siblings = data.filter(model => { return model.get('_parentId') === parentId; }); this._hasSiblingsAndSelf = true; @@ -693,7 +694,7 @@ export default class AdaptModel extends LockingModel { * @deprecated since v3.2.3 - please use `model.set('_isOptional', value)` instead */ setOptional(value) { - Adapt.log.deprecated('Use model.set(\'_isOptional\', value) as setOptional() may be removed in the future'); + logging.deprecated('Use model.set(\'_isOptional\', value) as setOptional() may be removed in the future'); this.set({ _isOptional: value }); } @@ -759,7 +760,7 @@ export default class AdaptModel extends LockingModel { if (!lockedBy) return false; return lockedBy.some(id => { try { - const anotherModel = Adapt.findById(id); + const anotherModel = data.findById(id); return anotherModel.get('_isAvailable') && ( anotherModel.get('_isLocked') || @@ -814,9 +815,9 @@ export default class AdaptModel extends LockingModel { clonedId = `${clonedId}_${cid}`; clonedModel.set('_id', clonedId); } - // Add the cloned model to Adapt.data for Adapt.findById resolution + // Add the cloned model to data for data.findById resolution if (hasId) { - Adapt.data.add(clonedModel); + data.add(clonedModel); } // Clone any children if (this.hasManagedChildren) { diff --git a/js/models/articleModel.js b/js/models/articleModel.js index e76f3c98..01eb21e8 100644 --- a/js/models/articleModel.js +++ b/js/models/articleModel.js @@ -1,20 +1,21 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; +import logging from 'core/js/logging'; import AdaptModel from 'core/js/models/adaptModel'; class ArticleModel extends AdaptModel { get _parent() { - Adapt.log.deprecated('articleModel._parent, use articleModel.getParent() instead, parent models are defined by the JSON'); + logging.deprecated('articleModel._parent, use articleModel.getParent() instead, parent models are defined by the JSON'); return 'contentObjects'; } get _siblings() { - Adapt.log.deprecated('articleModel._siblings, use articleModel.getSiblings() instead, sibling models are defined by the JSON'); + logging.deprecated('articleModel._siblings, use articleModel.getSiblings() instead, sibling models are defined by the JSON'); return 'articles'; } get _children() { - Adapt.log.deprecated('articleModel._children, use articleModel.hasManagedChildren instead, child models are defined by the JSON'); + logging.deprecated('articleModel._children, use articleModel.hasManagedChildren instead, child models are defined by the JSON'); return 'blocks'; } @@ -28,6 +29,6 @@ class ArticleModel extends AdaptModel { } -Adapt.register('article', { model: ArticleModel }); +components.register('article', { model: ArticleModel }); export default ArticleModel; diff --git a/js/models/blockModel.js b/js/models/blockModel.js index d8744f1f..65335059 100644 --- a/js/models/blockModel.js +++ b/js/models/blockModel.js @@ -1,20 +1,21 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; +import logging from 'core/js/logging'; import AdaptModel from 'core/js/models/adaptModel'; class BlockModel extends AdaptModel { get _parent() { - Adapt.log.deprecated('blockModel._parent, use blockModel.getParent() instead, parent models are defined by the JSON'); + logging.deprecated('blockModel._parent, use blockModel.getParent() instead, parent models are defined by the JSON'); return 'articles'; } get _siblings() { - Adapt.log.deprecated('blockModel._siblings, use blockModel.getSiblings() instead, sibling models are defined by the JSON'); + logging.deprecated('blockModel._siblings, use blockModel.getSiblings() instead, sibling models are defined by the JSON'); return 'blocks'; } get _children() { - Adapt.log.deprecated('blockModel._children, use blockModel.hasManagedChildren instead, child models are defined by the JSON'); + logging.deprecated('blockModel._children, use blockModel.hasManagedChildren instead, child models are defined by the JSON'); return 'components'; } @@ -28,6 +29,6 @@ class BlockModel extends AdaptModel { } -Adapt.register('block', { model: BlockModel }); +components.register('block', { model: BlockModel }); export default BlockModel; diff --git a/js/models/componentModel.js b/js/models/componentModel.js index d63e4f20..45b0c818 100644 --- a/js/models/componentModel.js +++ b/js/models/componentModel.js @@ -1,15 +1,17 @@ +import components from 'core/js/components'; import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; import AdaptModel from 'core/js/models/adaptModel'; class ComponentModel extends AdaptModel { get _parent() { - Adapt.log.deprecated('componentModel._parent, use componentModel.getParent() instead, parent models are defined by the JSON'); + logging.deprecated('componentModel._parent, use componentModel.getParent() instead, parent models are defined by the JSON'); return 'blocks'; } get _siblings() { - Adapt.log.deprecated('componentModel._siblings, use componentModel.getSiblings() instead, sibling models are defined by the JSON'); + logging.deprecated('componentModel._siblings, use componentModel.getSiblings() instead, sibling models are defined by the JSON'); return 'components'; } @@ -99,7 +101,7 @@ class ComponentModel extends AdaptModel { const types = this.trackableType(); trackables.find((name, index) => { // Exclude _attemptStates as it's trackable but isn't needed here - if (name !== '_attemptStates') return; + if (name !== '_attemptStates') return false; trackables.splice(index, 1); types.splice(index, 1); return true; @@ -125,7 +127,7 @@ class ComponentModel extends AdaptModel { const types = this.trackableType(); trackables.find((name, index) => { // Exclude _attemptStates as it's trackable but isn't needed here - if (name !== '_attemptStates') return; + if (name !== '_attemptStates') return false; trackables.splice(index, 1); types.splice(index, 1); return true; @@ -183,6 +185,6 @@ class ComponentModel extends AdaptModel { } // This abstract model needs to registered to support deprecated view-only components -Adapt.register('component', { model: ComponentModel }); +components.register('component', { model: ComponentModel }); export default ComponentModel; diff --git a/js/models/configModel.js b/js/models/configModel.js index b514695f..4bdf73ac 100644 --- a/js/models/configModel.js +++ b/js/models/configModel.js @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import wait from 'core/js/wait'; import LockingModel from 'core/js/models/lockingModel'; export default class ConfigModel extends LockingModel { @@ -45,7 +46,7 @@ export default class ConfigModel extends LockingModel { this.setValuesFromURLParams(); Adapt.trigger('offlineStorage:prepare'); - Adapt.wait.queue(() => { + wait.queue(() => { Adapt.trigger('configModel:dataLoaded'); if (!this.get('_canLoadData')) return; Adapt.trigger('configModel:loadCourseData'); diff --git a/js/models/contentObjectModel.js b/js/models/contentObjectModel.js index 74bee72c..43a248f9 100644 --- a/js/models/contentObjectModel.js +++ b/js/models/contentObjectModel.js @@ -1,10 +1,11 @@ import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; import AdaptModel from 'core/js/models/adaptModel'; export default class ContentObjectModel extends AdaptModel { get _parent() { - Adapt.log.deprecated('contentObjectModel._parent, use contentObjectModel.getParent() instead, parent models are defined by the JSON'); + logging.deprecated('contentObjectModel._parent, use contentObjectModel.getParent() instead, parent models are defined by the JSON'); const isParentCourse = (this.get('_parentId') === Adapt.course.get('_id')); if (isParentCourse) { return 'course'; @@ -13,12 +14,12 @@ export default class ContentObjectModel extends AdaptModel { } get _siblings() { - Adapt.log.deprecated('contentObjectModel._siblings, use contentObjectModel.getSiblings() instead, sibling models are defined by the JSON'); + logging.deprecated('contentObjectModel._siblings, use contentObjectModel.getSiblings() instead, sibling models are defined by the JSON'); return 'contentObjects'; } get _children() { - Adapt.log.deprecated('contentObjectModel._children, use contentObjectModel.hasManagedChildren instead, child models are defined by the JSON'); + logging.deprecated('contentObjectModel._children, use contentObjectModel.hasManagedChildren instead, child models are defined by the JSON'); return null; } diff --git a/js/models/courseModel.js b/js/models/courseModel.js index 28acf15a..64825688 100644 --- a/js/models/courseModel.js +++ b/js/models/courseModel.js @@ -1,20 +1,29 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; +import logging from 'core/js/logging'; import MenuModel from 'core/js/models/menuModel'; class CourseModel extends MenuModel { get _parent() { - Adapt.log.deprecated('courseModel._parent, use courseModel.getParent() instead, parent models are defined by the JSON'); + logging.deprecated('courseModel._parent, use courseModel.getParent() instead, parent models are defined by the JSON'); return null; } get _siblings() { - Adapt.log.deprecated('courseModel._siblings, use courseModel.getSiblings() instead, sibling models are defined by the JSON'); + logging.deprecated('courseModel._siblings, use courseModel.getSiblings() instead, sibling models are defined by the JSON'); return null; } + /** + * Returns a string of the model type group. + * @returns {string} + */ + getTypeGroup() { + return 'course'; + } + } -Adapt.register('course', { model: CourseModel }); +components.register('course', { model: CourseModel }); export default CourseModel; diff --git a/js/models/menuModel.js b/js/models/menuModel.js index e8676c57..12b7cc1d 100644 --- a/js/models/menuModel.js +++ b/js/models/menuModel.js @@ -1,10 +1,11 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; +import logging from 'core/js/logging'; import ContentObjectModel from 'core/js/models/contentObjectModel'; class MenuModel extends ContentObjectModel { get _children() { - Adapt.log.deprecated('menuModel._children, use menuModel.hasManagedChildren instead, child models are defined by the JSON'); + logging.deprecated('menuModel._children, use menuModel.hasManagedChildren instead, child models are defined by the JSON'); return 'contentObjects'; } @@ -27,6 +28,6 @@ class MenuModel extends ContentObjectModel { } -Adapt.register('menu', { model: MenuModel }); +components.register('menu', { model: MenuModel }); export default MenuModel; diff --git a/js/models/pageModel.js b/js/models/pageModel.js index 2ec1c9d7..fa69bdbd 100644 --- a/js/models/pageModel.js +++ b/js/models/pageModel.js @@ -1,10 +1,11 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; +import logging from 'core/js/logging'; import ContentObjectModel from 'core/js/models/contentObjectModel'; class PageModel extends ContentObjectModel { get _children() { - Adapt.log.deprecated('pageModel._children, use menuModel.hasManagedChildren instead, child models are defined by the JSON'); + logging.deprecated('pageModel._children, use menuModel.hasManagedChildren instead, child models are defined by the JSON'); return 'articles'; } @@ -18,6 +19,6 @@ class PageModel extends ContentObjectModel { } -Adapt.register('page', { model: PageModel }); +components.register('page', { model: PageModel }); export default PageModel; diff --git a/js/models/questionModel.js b/js/models/questionModel.js index 0d3e34ec..5ffeaee3 100644 --- a/js/models/questionModel.js +++ b/js/models/questionModel.js @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; import ComponentModel from 'core/js/models/componentModel'; import BUTTON_STATE from 'core/js/enums/buttonStateEnum'; @@ -396,6 +397,6 @@ class QuestionModel extends ComponentModel { } // This abstract model needs to registered to support deprecated view-only questions -Adapt.register('question', { model: QuestionModel }); +components.register('question', { model: QuestionModel }); export default QuestionModel; diff --git a/js/mpabc.js b/js/mpabc.js index 02a3f7e3..58ab3f67 100644 --- a/js/mpabc.js +++ b/js/mpabc.js @@ -1,10 +1,12 @@ import Adapt from 'core/js/adapt'; +import wait from 'core/js/wait'; import Data from 'core/js/data'; import AdaptSubsetCollection from 'core/js/collections/adaptSubsetCollection'; import ContentObjectModel from 'core/js/models/contentObjectModel'; import ArticleModel from 'core/js/models/articleModel'; import BlockModel from 'core/js/models/blockModel'; import ComponentModel from 'core/js/models/componentModel'; +import logging from 'core/js/logging'; import 'core/js/models/courseModel'; import 'core/js/models/menuModel'; @@ -26,12 +28,12 @@ class MPABC extends Backbone.Controller { waitForDataLoaded() { // Tell the data loader to wait - Adapt.wait.begin(); + wait.begin(); } onDataLoaded() { // Tell the data loader that we have finished - Adapt.wait.end(); + wait.end(); } setupSubsetCollections() { @@ -43,4 +45,13 @@ class MPABC extends Backbone.Controller { } -export default (Adapt.mpabc = new MPABC()); +const mpabc = new MPABC(); + +Object.defineProperty(Adapt, 'mpabc', { + get() { + logging.deprecated('Adapt.mpabc, please use core/js/mpabc directly'); + return mpabc; + } +}); + +export default mpabc; diff --git a/js/notify.js b/js/notify.js index 4ebaf0b8..dd63186f 100644 --- a/js/notify.js +++ b/js/notify.js @@ -1,5 +1,14 @@ -import Backbone from 'backbone'; import Adapt from 'core/js/adapt'; -import NotifyView from './views/notifyView'; +import NotifyView from 'core/js/views/notifyView'; +import logging from 'core/js/logging'; -export default (Adapt.notify = new NotifyView()); +const notify = new NotifyView(); + +Object.defineProperty(Adapt, 'notify', { + get() { + logging.deprecated('Adapt.notify, please use core/js/notify directly'); + return notify; + } +}); + +export default notify; diff --git a/js/offlineStorage.js b/js/offlineStorage.js index 33444513..a058aa05 100644 --- a/js/offlineStorage.js +++ b/js/offlineStorage.js @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; // Basic API for setting and getting name+value pairs // Allows registration of a single handler. @@ -91,6 +92,13 @@ class OfflineStorage extends Backbone.Controller { } -Adapt.offlineStorage = new OfflineStorage(); +const offlineStorage = new OfflineStorage(); -export default Adapt.offlineStorage; +Object.defineProperty(Adapt, 'offlineStorage', { + get() { + logging.deprecated('offlineStorage, please use src/core/offlineStorage instead'); + return offlineStorage; + } +}); + +export default offlineStorage; diff --git a/js/reactHelpers.js b/js/reactHelpers.js index d5d4bf7c..fa2397ce 100644 --- a/js/reactHelpers.js +++ b/js/reactHelpers.js @@ -1,7 +1,7 @@ import Adapt from 'core/js/adapt'; -import TemplateRenderEvent from './templateRenderEvent'; +import TemplateRenderEvent from 'core/js/templateRenderEvent'; import React from 'react'; -import logging from './logging'; +import logging from 'core/js/logging'; /** * Used by babel plugin babel-plugin-transform-react-templates to inject react templates diff --git a/js/router.js b/js/router.js index 3b533fb0..4ec2e5be 100644 --- a/js/router.js +++ b/js/router.js @@ -1,9 +1,11 @@ import Adapt from 'core/js/adapt'; +import wait from 'core/js/wait'; +import components from 'core/js/components'; +import data from 'core/js/data'; +import a11y from 'core/js/a11y'; import RouterModel from 'core/js/models/routerModel'; -import CourseModel from 'core/js/models/courseModel'; -import ContentObjectModel from 'core/js/models/contentObjectModel'; -import MenuModel from 'core/js/models/menuModel'; -import 'core/js/startController'; +import logging from 'core/js/logging'; +import location from 'core/js/location'; class Router extends Backbone.Router { @@ -46,8 +48,8 @@ class Router extends Backbone.Router { } setDocumentTitle() { - const currentModel = Adapt.location._currentModel; - const hasSubTitle = (currentModel && currentModel !== Adapt.router.rootModel && currentModel.get('title')); + const currentModel = location._currentModel; + const hasSubTitle = (currentModel && currentModel !== router.rootModel && currentModel.get('title')); const title = [ this.rootModel.get('title'), hasSubTitle && currentModel.get('title') @@ -61,7 +63,7 @@ class Router extends Backbone.Router { navigateToArguments(args) { args = args.filter(v => v !== null); const options = { trigger: false, replace: false }; - if (args.length === 1 && Adapt.findById(args[0])) { + if (args.length === 1 && data.findById(args[0])) { this.navigate('#/id/' + args[0], options); return; } @@ -69,7 +71,7 @@ class Router extends Backbone.Router { this.navigate('#/' + args.join('/'), options); return; } - Adapt.log.deprecated('Use Backbone.history.navigate or window.location.href instead of Adapt.trigger(\'router:navigateTo\')'); + logging.deprecated('Use Backbone.history.navigate or window.location.href instead of Adapt.trigger(\'router:navigateTo\')'); this.handleRoute(...args); } @@ -131,8 +133,8 @@ class Router extends Backbone.Router { } async handleId(id) { - const rootModel = Adapt.router.rootModel; - let model = (!id) ? rootModel : Adapt.findById(id); + const rootModel = router.rootModel; + let model = (!id) ? rootModel : data.findById(id); if (!model) { // Bad id @@ -141,7 +143,7 @@ class Router extends Backbone.Router { } // Keep the routed id incase it needs to be scrolled to later - const isContentObject = (model instanceof ContentObjectModel); + const isContentObject = model.isTypeGroup?.('contentobject'); const navigateToId = model.get('_id'); // Ensure that the router is rendering a contentobject @@ -159,9 +161,9 @@ class Router extends Backbone.Router { if (model.get('_isLocked') && Adapt.config.get('_forceRouteLocking')) { // Locked id - Adapt.log.warn('Unable to navigate to locked id: ' + id); + logging.warn('Unable to navigate to locked id: ' + id); this.model.set('_canNavigate', true, { pluginName: 'adapt' }); - if (Adapt.location._previousId === undefined) { + if (location._previousId === undefined) { return this.navigate('#/', { trigger: true, replace: true }); } return this.navigateBack(); @@ -174,15 +176,15 @@ class Router extends Backbone.Router { /** * TODO: * As the course object has separate location and type rules, - * it makes it more difficult to update the Adapt.location object + * it makes it more difficult to update the location object * should stop doing this. */ - const isCourse = (model instanceof CourseModel); + const isCourse = model.isTypeGroup?.('course'); const type = isCourse ? 'menu' : model.get('_type'); - const location = isCourse ? 'course' : `${type}-${id}`; + const newLocation = isCourse ? 'course' : `${type}-${id}`; model.set('_isVisited', true); - await this.updateLocation(location, type, id, model); + await this.updateLocation(newLocation, type, id, model); Adapt.once('contentObjectView:ready', () => { // Allow navigation. @@ -191,10 +193,10 @@ class Router extends Backbone.Router { }); Adapt.trigger(`router:${type} router:contentObject`, model); - const ViewClass = Adapt.getViewClass(model); - const isMenu = (model instanceof MenuModel); + const ViewClass = components.getViewClass(model); + const isMenu = model.isTypeGroup?.('menu'); if (!ViewClass && isMenu) { - Adapt.log.deprecated(`Using event based menu view instantiation for '${Adapt.getViewName(model)}'`); + logging.deprecated(`Using event based menu view instantiation for '${components.getViewName(model)}'`); return; } @@ -209,21 +211,21 @@ class Router extends Backbone.Router { if (!isContentObject && !this.isScrolling) { // Scroll to element if not a content object or not already trying to - await Adapt.navigateToElement('.' + navigateToId, { replace: true, duration: 400 }); + await this.navigateToElement('.' + navigateToId, { replace: true, duration: 400 }); } } async updateLocation(currentLocation, type, id, currentModel) { // Handles updating the location. - Adapt.location._previousModel = Adapt.location._currentModel; - Adapt.location._previousId = Adapt.location._currentId; - Adapt.location._previousContentType = Adapt.location._contentType; + location._previousModel = location._currentModel; + location._previousId = location._currentId; + location._previousContentType = location._contentType; - Adapt.location._currentModel = currentModel; - Adapt.location._currentId = id; - Adapt.location._contentType = type; - Adapt.location._currentLocation = currentLocation; + location._currentModel = currentModel; + location._currentId = id; + location._contentType = type; + location._currentLocation = currentLocation; /** * TODO: @@ -231,49 +233,49 @@ class Router extends Backbone.Router { * these properties are unused in the framework */ if (type === 'menu') { - Adapt.location._lastVisitedType = 'menu'; - Adapt.location._lastVisitedMenu = id; + location._lastVisitedType = 'menu'; + location._lastVisitedMenu = id; } else if (type === 'page') { - Adapt.location._lastVisitedType = 'page'; - Adapt.location._lastVisitedPage = id; + location._lastVisitedType = 'page'; + location._lastVisitedPage = id; } this.setDocumentTitle(); this.setGlobalClasses(); // Trigger event when location changes. - Adapt.trigger('router:location', Adapt.location); + Adapt.trigger('router:location', location); - await Adapt.wait.queue(); + await wait.queue(); } setGlobalClasses() { - const currentModel = Adapt.location._currentModel; + const currentModel = location._currentModel; const htmlClasses = currentModel?.get('_htmlClasses') || ''; - const classes = (Adapt.location._currentId) ? - `location-${Adapt.location._contentType} location-id-${Adapt.location._currentId}` : - `location-${Adapt.location._currentLocation}`; + const classes = (location._currentId) ? + `location-${location._contentType} location-id-${location._currentId}` : + `location-${location._currentLocation}`; const currentClasses = `${classes} ${htmlClasses}`; this.$html - .removeClass(Adapt.location._previousClasses) + .removeClass(location._previousClasses) .addClass(currentClasses) - .attr('data-location', Adapt.location._currentLocation); + .attr('data-location', location._currentLocation); this.$wrapper .removeClass() .addClass(classes) - .attr('data-location', Adapt.location._currentLocation); + .attr('data-location', location._currentLocation); - Adapt.location._previousClasses = currentClasses; + location._previousClasses = currentClasses; } handleNavigationFocus() { if (!this.model.get('_shouldNavigateFocus')) return; // Body will be forced to accept focus to start the // screen reader reading the page. - Adapt.a11y.focus('body'); + a11y.focus('body'); } navigateBack() { @@ -285,11 +287,11 @@ class Router extends Backbone.Router { if (!this.model.get('_canNavigate') && !force) { return; } - if (!Adapt.location._currentId) { + if (!location._currentId) { return; } - const currentId = Adapt.location._currentModel.get('_id'); - const isRoot = (Adapt.location._currentModel === this.rootModel); + const currentId = location._currentModel.get('_id'); + const isRoot = (location._currentModel === this.rootModel); const route = isRoot ? '#/' : '#/id/' + currentId; this.navigate(route, { trigger: true, replace: true }); } @@ -300,12 +302,12 @@ class Router extends Backbone.Router { if (!this.model.get('_canNavigate') && !force) { return; } - const currentModel = Adapt.location._currentModel; - const previousModel = Adapt.location._previousModel; + const currentModel = location._currentModel; + const previousModel = location._previousModel; if (!currentModel) { return this.navigateBack(); } - if (Adapt.location._currentModel instanceof MenuModel) { + if (location._currentModel?.isTypeGroup('menu')) { return this.navigateToParent(); } if (previousModel) { @@ -318,8 +320,8 @@ class Router extends Backbone.Router { if (!this.model.get('_canNavigate') && !force) { return; } - const parentId = Adapt.location._currentModel.get('_parentId'); - const parentModel = Adapt.findById(parentId); + const parentId = location._currentModel.get('_parentId'); + const parentModel = data.findById(parentId); const isRoot = (parentModel === this.rootModel); const route = isRoot ? '#/' : '#/id/' + parentId; this.navigate(route, { trigger: true }); @@ -335,20 +337,19 @@ class Router extends Backbone.Router { /** * Allows a selector or id to be passed in and Adapt will navigate to this element. Resolves * asynchronously when the element has been navigated to. - * Backend for Adapt.navigateToElement * @param {string} selector CSS selector or id of the Adapt element you want to navigate to e.g. `".co-05"` or `"co-05"` * @param {Object} [settings] The settings for the `$.scrollTo` function (See https://github.com/flesler/jquery.scrollTo#settings). * @param {Object} [settings.replace=false] Set to `true` if you want to update the URL without creating an entry in the browser's history. */ async navigateToElement(selector, settings = {}) { const currentModelId = selector.replace(/\./g, '').split(' ')[0]; - const currentModel = Adapt.findById(currentModelId); + const currentModel = data.findById(currentModelId); if (currentModel && (!currentModel.get('_isRendered') || !currentModel.get('_isReady'))) { const shouldReplace = settings.replace || false; - const contentObject = (currentModel instanceof ContentObjectModel) ? currentModel : currentModel.findAncestor('contentobject'); + const contentObject = currentModel.isTypeGroup?.('contentobject') ? currentModel : currentModel.findAncestor('contentobject'); const contentObjectId = contentObject.get('_id'); - const isNotInCurrentContentObject = (contentObjectId !== Adapt.location._currentId); + const isNotInCurrentContentObject = (contentObjectId !== location._currentId); if (isNotInCurrentContentObject) { this.isScrolling = true; this.navigate(`#/id/${currentModelId}`, { trigger: true, replace: shouldReplace }); @@ -368,11 +369,11 @@ class Router extends Backbone.Router { } // Get the current location - this is set in the router - const location = (Adapt.location._contentType) - ? Adapt.location._contentType - : Adapt.location._currentLocation; + const newLocation = (location._contentType) + ? location._contentType + : location._currentLocation; // Trigger initial scrollTo event - Adapt.trigger(`${location}:scrollTo`, selector); + Adapt.trigger(`${newLocation}:scrollTo`, selector); // Setup duration variable const disableScrollToAnimation = Adapt.config.has('_disableAnimation') ? Adapt.config.get('_disableAnimation') : false; if (disableScrollToAnimation) { @@ -404,7 +405,7 @@ class Router extends Backbone.Router { // 300 milliseconds added to make sure queue has finished await new Promise(resolve => { _.delay(() => { - Adapt.a11y.focusNext(selector); + a11y.focusNext(selector); Adapt.trigger(`${location}:scrolledTo`, selector); resolve(); }, settings.duration + 300); @@ -412,21 +413,36 @@ class Router extends Backbone.Router { } get(...args) { - Adapt.log.deprecated('Adapt.router.get, please use Adapt.router.model.get'); + logging.deprecated('router.get, please use router.model.get'); return this.model.get(...args); } set(...args) { - Adapt.log.deprecated('Adapt.router.set, please use Adapt.router.model.set'); + logging.deprecated('router.set, please use router.model.set'); return this.model.set(...args); } } -Adapt.router = new Router({ +const router = new Router({ model: new RouterModel(null, { reset: true }) }); -Adapt.navigateToElement = Adapt.router.navigateToElement.bind(Adapt.router); +router.navigateToElement = router.navigateToElement.bind(router); -export default Adapt.router; +Object.defineProperties(Adapt, { + navigateToElement: { + get() { + logging.deprecated('Adapt.navigateToElement, please use router.navigateToElement'); + return router.navigateToElement; + } + }, + router: { + get() { + logging.deprecated('router, please use core/js/router directly'); + return router; + } + } +}); + +export default router; diff --git a/js/scrolling.js b/js/scrolling.js index 18a487ed..9ac1e5ea 100644 --- a/js/scrolling.js +++ b/js/scrolling.js @@ -1,4 +1,6 @@ import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; +import router from 'core/js/router'; /** * This allows Adapt to: @@ -119,20 +121,34 @@ class Scrolling extends Backbone.Controller { /** * Allows a selector to be passed in and Adapt will scroll to this element. Resolves * asynchronously when the element has been navigated/scrolled to. - * Backend for Adapt.scrollTo * @param {string} selector CSS selector of the Adapt element you want to navigate to e.g. `".co-05"` * @param {Object} [settings={}] The settings for the `$.scrollTo` function (See https://github.com/flesler/jquery.scrollTo#settings). * @param {Object} [settings.replace=false] Set to `true` if you want to update the URL without creating an entry in the browser's history. */ async scrollTo(selector, settings = {}) { - Adapt.log.deprecated('Adapt.scrollTo and Adapt.scrolling.scrollTo, use Adapt.navigateToElement instead.'); - return Adapt.router.navigateToElement(selector, settings); + logging.deprecated('Adapt.scrollTo and Adapt.scrolling.scrollTo, use router.navigateToElement instead.'); + return router.navigateToElement(selector, settings); } } -Adapt.scrolling = new Scrolling(); +const scrolling = new Scrolling(); -Adapt.scrollTo = Adapt.scrolling.scrollTo.bind(Adapt.scrolling); +scrolling.scrollTo = scrolling.scrollTo.bind(scrolling); -export default Adapt.scrolling; +Object.defineProperties(Adapt, { + scrolling: { + get() { + logging.deprecated('Adapt.scrolling, please use core/js/scrolling directly'); + return scrolling; + } + }, + scrollTo: { + get() { + logging.deprecated('Adapt.scrollTo, please use router.navigateToElement'); + return scrolling.scrollTo; + } + } +}); + +export default scrolling; diff --git a/js/startController.js b/js/startController.js index f6c0602d..06190f7d 100644 --- a/js/startController.js +++ b/js/startController.js @@ -1,5 +1,9 @@ import Adapt from 'core/js/adapt'; +import wait from 'core/js/wait'; import LockingModel from 'core/js/models/lockingModel'; +import logging from 'core/js/logging'; +import router from 'core/js/router'; +import data from 'core/js/data'; class StartController extends Backbone.Controller { @@ -61,7 +65,7 @@ class StartController extends Backbone.Controller { const className = item._className; const skipIfComplete = item._skipIfComplete; - const model = Adapt.findById(item._id); + const model = data.findById(item._id); if (!model) { console.log('startController: cannot find id', item._id); @@ -85,8 +89,8 @@ class StartController extends Backbone.Controller { } Adapt.once('adapt:start', () => { - Adapt.startController.loadCourseData(); - Adapt.startController.setStartLocation(); + startController.loadCourseData(); + startController.setStartLocation(); }); /* @@ -94,7 +98,25 @@ Adapt.once('adapt:start', () => { * or by including in the top navigation bar a button that has the attribute `data-event="returnToStart"` */ Adapt.on('navigation:returnToStart', () => { - Adapt.startController.returnToStartLocation(); + startController.returnToStartLocation(); }); -export default (Adapt.startController = new StartController()); +Adapt.on('app:languageChanged', () => { + wait.for(done => { + startController.loadCourseData(); + const hash = startController.isEnabled() ? startController.getStartHash(false) : '#/'; + router.navigate(hash, { trigger: true, replace: true }); + done(); + }); +}); + +const startController = new StartController(); + +Object.defineProperty(Adapt, 'startController', { + get() { + logging.deprecated('Adapt.startController, please use core/js/startController directly'); + return startController; + } +}); + +export default startController; diff --git a/js/tracking.js b/js/tracking.js index 1431c5db..dbc5d792 100644 --- a/js/tracking.js +++ b/js/tracking.js @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import offlineStorage from 'core/js/offlineStorage'; import logging from 'core/js/logging'; import COMPLETION_STATE from 'core/js/enums/completionStateEnum'; @@ -46,11 +47,11 @@ class Tracking extends Backbone.Controller { if (!this._config._shouldSubmitScore) return; if (this._assessmentState.isPercentageBased) { - Adapt.offlineStorage.set('score', this._assessmentState.scoreAsPercent, 0, 100); + offlineStorage.set('score', this._assessmentState.scoreAsPercent, 0, 100); return; } - Adapt.offlineStorage.set('score', this._assessmentState.score, this._assessmentState.minScore, this._assessmentState.maxScore); + offlineStorage.set('score', this._assessmentState.score, this._assessmentState.minScore, this._assessmentState.maxScore); } /** @@ -72,7 +73,7 @@ class Tracking extends Backbone.Controller { } Adapt.trigger('tracking:complete', completionData); - Adapt.log.debug('tracking:complete', completionData); + logging.debug('tracking:complete', completionData); } /** @@ -125,6 +126,13 @@ class Tracking extends Backbone.Controller { } -Adapt.tracking = new Tracking(); +const tracking = new Tracking(); -export default Adapt.tracking; +Object.defineProperty(Adapt, 'tracking', { + get() { + logging.deprecated('Adapt.tracking, please use core/js/tracking directly'); + return tracking; + } +}); + +export default tracking; diff --git a/js/views/adaptView.js b/js/views/adaptView.js index b0d530c9..40313805 100644 --- a/js/views/adaptView.js +++ b/js/views/adaptView.js @@ -1,8 +1,12 @@ import Adapt from 'core/js/adapt'; +import wait from 'core/js/wait'; +import components from 'core/js/components'; import ChildEvent from 'core/js/childEvent'; import { templates } from 'core/js/reactHelpers'; import React from 'react'; import ReactDOM from 'react-dom'; +import location from 'core/js/location'; +import logging from 'core/js/logging'; class AdaptView extends Backbone.View { @@ -33,7 +37,7 @@ class AdaptView extends Backbone.View { }); this._isRemoved = false; - if (Adapt.location._currentId === this.model.get('_id')) { + if (location._currentId === this.model.get('_id')) { Adapt.parentView = this; } @@ -158,7 +162,7 @@ class AdaptView extends Backbone.View { _nthChild: ++this.nthChild }); // Create child view - const ChildView = this.constructor.childView || Adapt.getViewClass(model); + const ChildView = this.constructor.childView || components.getViewClass(model); if (!ChildView) { throw new Error(`The component '${model.attributes._id}' ('${model.attributes._component}') has not been installed, and so is not available in your project.`); } @@ -338,7 +342,7 @@ class AdaptView extends Backbone.View { this._isRemoved = true; this.stopListening(); - Adapt.wait.for(end => { + wait.for(end => { if (this.isJSX) { ReactDOM.unmountComponentAtNode(this.el); } @@ -395,7 +399,7 @@ class AdaptView extends Backbone.View { * @returns {{ view.model.get('_id')); } @@ -407,7 +411,7 @@ class AdaptView extends Backbone.View { * @deprecated since 5.7.0 */ set childViews(value) { - Adapt.log.deprecated('view.childViews use view.getChildViews() and view.setChildViews([])'); + logging.deprecated('view.childViews use view.getChildViews() and view.setChildViews([])'); this.setChildViews(value); } diff --git a/js/views/articleView.js b/js/views/articleView.js index b0b43104..4c3ba853 100644 --- a/js/views/articleView.js +++ b/js/views/articleView.js @@ -1,4 +1,4 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; import AdaptView from 'core/js/views/adaptView'; class ArticleView extends AdaptView { @@ -23,6 +23,6 @@ Object.assign(ArticleView, { template: 'article' }); -Adapt.register('article', { view: ArticleView }); +components.register('article', { view: ArticleView }); export default ArticleView; diff --git a/js/views/blockView.js b/js/views/blockView.js index 277e6210..9ffe8b12 100644 --- a/js/views/blockView.js +++ b/js/views/blockView.js @@ -1,4 +1,4 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; import AdaptView from 'core/js/views/adaptView'; class BlockView extends AdaptView { @@ -23,6 +23,6 @@ Object.assign(BlockView, { template: 'block' }); -Adapt.register('block', { view: BlockView }); +components.register('block', { view: BlockView }); export default BlockView; diff --git a/js/views/buttonsView.js b/js/views/buttonsView.js index 05aa4488..8eff3af0 100644 --- a/js/views/buttonsView.js +++ b/js/views/buttonsView.js @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import a11y from 'core/js/a11y'; import BUTTON_STATE from 'core/js/enums/buttonStateEnum'; // convert BUTTON_STATE to property name @@ -57,7 +58,7 @@ export default class ButtonsView extends Backbone.View { this.$('.js-btn-marking').removeClass('is-incorrect is-correct').addClass('u-display-none'); this.$el.removeClass('is-submitted'); this.model.set('feedbackMessage', undefined); - Adapt.a11y.toggleEnabled(this.$('.js-btn-feedback'), false); + a11y.toggleEnabled(this.$('.js-btn-feedback'), false); } onActionClicked() { @@ -83,11 +84,11 @@ export default class ButtonsView extends Backbone.View { onFeedbackMessageChanged(model, changedAttribute) { if (changedAttribute && this.model.get('_canShowFeedback')) { // enable feedback button - Adapt.a11y.toggleEnabled(this.$('.js-btn-feedback'), true); + a11y.toggleEnabled(this.$('.js-btn-feedback'), true); return; } // disable feedback button - Adapt.a11y.toggleEnabled(this.$('.js-btn-feedback'), false); + a11y.toggleEnabled(this.$('.js-btn-feedback'), false); } onCanSubmitChange() { @@ -103,7 +104,7 @@ export default class ButtonsView extends Backbone.View { const buttonState = BUTTON_STATE(changedAttribute); if (changedAttribute === BUTTON_STATE.CORRECT || changedAttribute === BUTTON_STATE.INCORRECT) { // Both 'correct' and 'incorrect' states have no model answer, so disable the submit button - Adapt.a11y.toggleEnabled($buttonsAction, false); + a11y.toggleEnabled($buttonsAction, false); return; } @@ -112,7 +113,7 @@ export default class ButtonsView extends Backbone.View { const buttonText = this.model.get('_buttons')['_' + propertyName].buttonText; // Enable the button, make accessible and update aria labels and text - Adapt.a11y.toggleEnabled($buttonsAction, this.model.get('_canSubmit')); + a11y.toggleEnabled($buttonsAction, this.model.get('_canSubmit')); $buttonsAction.html(buttonText).attr('aria-label', ariaLabel); } diff --git a/js/views/componentView.js b/js/views/componentView.js index abbfb290..9d4a568d 100644 --- a/js/views/componentView.js +++ b/js/views/componentView.js @@ -1,4 +1,4 @@ -import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; import AdaptView from 'core/js/views/adaptView'; class ComponentView extends AdaptView { @@ -9,7 +9,7 @@ class ComponentView extends AdaptView { } return AdaptView.resultExtend('attributes', { 'aria-labelledby': this.model.get('_id') + '-heading', - 'role': 'region' + role: 'region' }, this); } @@ -28,7 +28,7 @@ class ComponentView extends AdaptView { } renderState() { - Adapt.log.removed('renderState is removed and moved to item title'); + logging.removed('renderState is removed and moved to item title'); } /** diff --git a/js/views/contentObjectView.js b/js/views/contentObjectView.js index c9e4836b..a2f56c72 100644 --- a/js/views/contentObjectView.js +++ b/js/views/contentObjectView.js @@ -1,11 +1,13 @@ import Adapt from 'core/js/adapt'; +import wait from 'core/js/wait'; import AdaptView from 'core/js/views/adaptView'; +import ReactDOM from 'react-dom'; export default class ContentObjectView extends AdaptView { attributes() { return AdaptView.resultExtend('attributes', { - 'role': 'main', + role: 'main', 'aria-labelledby': `${this.model.get('_id')}-heading` }, this); } @@ -63,7 +65,7 @@ export default class ContentObjectView extends AdaptView { const type = this.constructor.type; const performIsReady = async () => { Adapt.trigger(`${type}View:preReady contentObjectView:preReady view:preReady`, this); - await Adapt.wait.queue(); + await wait.queue(); $('.js-loading').hide(); if (Adapt.get('_shouldContentObjectScrollTop') !== false) { $(window).scrollTop(0); @@ -142,7 +144,7 @@ export default class ContentObjectView extends AdaptView { Adapt.trigger(`${type}View:remove contentObjectView:remove view:remove`, this); this._isRemoved = true; - Adapt.wait.for(end => { + wait.for(end => { if (this.isReact) { ReactDOM.unmountComponentAtNode(this.el); } diff --git a/js/views/drawerView.js b/js/views/drawerView.js index 6cc54620..57f6bbd2 100644 --- a/js/views/drawerView.js +++ b/js/views/drawerView.js @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import a11y from 'core/js/a11y'; import DrawerItemView from 'core/js/views/drawerItemView'; class DrawerView extends Backbone.View { @@ -9,7 +10,7 @@ class DrawerView extends Backbone.View { attributes() { return { - 'role': 'dialog', + role: 'dialog', 'aria-modal': 'true', 'aria-labelledby': 'drawer-heading', 'aria-hidden': 'true' @@ -30,7 +31,7 @@ class DrawerView extends Backbone.View { 'navigation:toggleDrawer': this.toggleDrawer, 'drawer:triggerCustomView': this.openCustomView, 'drawer:closeDrawer': this.onCloseDrawer, - 'remove': this.onRemove, + remove: this.onRemove, 'drawer:remove': this.remove }); @@ -117,8 +118,8 @@ class DrawerView extends Backbone.View { this.$el.removeClass('u-display-none').removeAttr('aria-hidden'); // Only trigger popup:opened if drawer is visible, pass popup manager drawer element if (!this._isVisible) { - Adapt.a11y.popupOpened(this.$el); - Adapt.a11y.scrollDisable('body'); + a11y.popupOpened(this.$el); + a11y.scrollDisable('body'); this._isVisible = true; } @@ -152,7 +153,7 @@ class DrawerView extends Backbone.View { Adapt.trigger('drawer:opened'); // focus on first tabbable element in drawer - Adapt.a11y.focusFirst(this.$el, { defer: true }); + a11y.focusFirst(this.$el, { defer: true }); }; // delay drawer animation until after background fadeout animation is complete @@ -195,9 +196,9 @@ class DrawerView extends Backbone.View { if (!this._isVisible) return; const direction = {}; - Adapt.a11y.popupClosed($toElement); + a11y.popupClosed($toElement); this._isVisible = false; - Adapt.a11y.scrollEnable('body'); + a11y.scrollEnable('body'); if (this.disableAnimation) { @@ -223,7 +224,8 @@ class DrawerView extends Backbone.View { Adapt.trigger('drawer:closed'); }); - $('.js-shadow').velocity({ opacity: 0 }, { duration: this.drawerDuration, + $('.js-shadow').velocity({ opacity: 0 }, { + duration: this.drawerDuration, complete() { $('.js-shadow').addClass('u-display-none'); } diff --git a/js/views/navigationView.js b/js/views/navigationView.js index 789e447f..44547012 100644 --- a/js/views/navigationView.js +++ b/js/views/navigationView.js @@ -1,4 +1,8 @@ import Adapt from 'core/js/adapt'; +import a11y from 'core/js/a11y'; +import location from 'core/js/location'; +import router from 'core/js/router'; +import startController from 'core/js/startController'; class NavigationView extends Backbone.View { @@ -52,25 +56,25 @@ class NavigationView extends Backbone.View { Adapt.trigger('navigation:' + currentEvent); switch (currentEvent) { case 'backButton': - Adapt.router.navigateToPreviousRoute(); + router.navigateToPreviousRoute(); break; case 'homeButton': - Adapt.router.navigateToHomeRoute(); + router.navigateToHomeRoute(); break; case 'parentButton': - Adapt.router.navigateToParent(); + router.navigateToParent(); break; case 'skipNavigation': this.skipNavigation(); break; case 'returnToStart': - Adapt.startController.returnToStartLocation(); + startController.returnToStartLocation(); break; } } skipNavigation() { - Adapt.a11y.focusFirst('.' + Adapt.location._contentType); + a11y.focusFirst('.' + location._contentType); } onNavigate(model) { diff --git a/js/views/notifyPopupView.js b/js/views/notifyPopupView.js index 1785ec01..3f2b7da5 100644 --- a/js/views/notifyPopupView.js +++ b/js/views/notifyPopupView.js @@ -1,4 +1,7 @@ import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; +import data from 'core/js/data'; +import a11y from 'core/js/a11y'; import AdaptView from 'core/js/views/adaptView'; import Backbone from 'backbone'; @@ -25,7 +28,8 @@ export default class NotifyPopupView extends Backbone.View { }; } - initialize() { + initialize({ notify }) { + this.notify = notify; _.bindAll(this, 'resetNotifySize', 'onKeyUp'); this.disableAnimation = Adapt.config.get('_disableAnimation') || false; this.isOpen = false; @@ -125,7 +129,7 @@ export default class NotifyPopupView extends Backbone.View { this.isOpen = true; await this.addSubView(); // Add to the list of open popups - Adapt.notify.stack.push(this); + this.notify.stack.push(this); // Keep focus from previous action this.$previousActiveElement = $(document.activeElement); Adapt.trigger('notify:opened', this); @@ -164,19 +168,19 @@ export default class NotifyPopupView extends Backbone.View { $.inview(); this.hasOpened = true; // Allows popup manager to control focus - Adapt.a11y.popupOpened(this.$('.notify__popup')); - Adapt.a11y.scrollDisable('body'); + a11y.popupOpened(this.$('.notify__popup')); + a11y.scrollDisable('body'); $('html').addClass('notify'); // Set focus to first accessible element - Adapt.a11y.focusFirst(this.$('.notify__popup'), { defer: false }); + a11y.focusFirst(this.$('.notify__popup'), { defer: false }); } async addSubView() { this.subView = this.model.get('_view'); if (this.model.get('_id')) { // Automatically render the specified id - const model = Adapt.findById(this.model.get('_id')); - const View = Adapt.getViewClass(model); + const model = data.findById(this.model.get('_id')); + const View = components.getViewClass(model); this.subView = new View({ model }); } if (!this.subView) return; @@ -196,9 +200,9 @@ export default class NotifyPopupView extends Backbone.View { closeNotify() { // Make sure that only the top most notify is closed - const stackItem = Adapt.notify.stack[Adapt.notify.stack.length - 1]; + const stackItem = this.notify.stack[this.notify.stack.length - 1]; if (this !== stackItem) return; - Adapt.notify.stack.pop(); + this.notify.stack.pop(); // Prevent from being invoked multiple times - see https://github.com/adaptlearning/adapt_framework/issues/1659 if (!this.isOpen) return; this.isOpen = false; @@ -234,10 +238,10 @@ export default class NotifyPopupView extends Backbone.View { } }); } - Adapt.a11y.scrollEnable('body'); + a11y.scrollEnable('body'); $('html').removeClass('notify'); // Return focus to previous active element - Adapt.a11y.popupClosed(this.$previousActiveElement); + a11y.popupClosed(this.$previousActiveElement); // Return reference to the notify view Adapt.trigger('notify:closed', this); } diff --git a/js/views/notifyView.js b/js/views/notifyView.js index f07a5d06..a435499e 100644 --- a/js/views/notifyView.js +++ b/js/views/notifyView.js @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import logging from 'core/js/logging'; import NotifyPushCollection from 'core/js/collections/notifyPushCollection'; import NotifyPopupView from 'core/js/views/notifyPopupView'; import NotifyModel from 'core/js/models/notifyModel'; @@ -26,7 +27,7 @@ export default class NotifyView extends Backbone.View { } _deprecated(type, notifyObject) { - Adapt.log.deprecated(`NOTIFY DEPRECATED: Adapt.trigger('notify:${type}', notifyObject); is no longer supported, please use Adapt.notify.${type}(notifyObject);`); + logging.deprecated(`NOTIFY DEPRECATED: Adapt.trigger('notify:${type}', notifyObject); is no longer supported, please use notify.${type}(notifyObject);`); return this.create(notifyObject, { _type: type }); } @@ -50,7 +51,8 @@ export default class NotifyView extends Backbone.View { } return new NotifyPopupView({ - model: new NotifyModel(notifyObject) + model: new NotifyModel(notifyObject), + notify: this }); } diff --git a/js/views/pageView.js b/js/views/pageView.js index ddb73cb8..32058510 100644 --- a/js/views/pageView.js +++ b/js/views/pageView.js @@ -1,4 +1,4 @@ -import Adapt from 'core/js/adapt'; +import components from 'core/js/components'; import ContentObjectView from 'core/js/views/contentObjectView'; class PageView extends ContentObjectView { @@ -18,6 +18,6 @@ Object.assign(PageView, { template: 'page' }); -Adapt.register('page', { view: PageView }); +components.register('page', { view: PageView }); export default PageView; diff --git a/js/views/questionView.js b/js/views/questionView.js index 8cf3d5c4..18e82ca5 100644 --- a/js/views/questionView.js +++ b/js/views/questionView.js @@ -2,8 +2,10 @@ import Adapt from 'core/js/adapt'; import ComponentView from 'core/js/views/componentView'; import ButtonsView from 'core/js/views/buttonsView'; import BUTTON_STATE from 'core/js/enums/buttonStateEnum'; -import a11y from '../a11y'; -import log from '../logging'; +import a11y from 'core/js/a11y'; +import log from 'core/js/logging'; +import data from 'core/js/data'; +import location from 'core/js/location'; import 'core/js/models/questionModel'; class QuestionView extends ComponentView { @@ -290,7 +292,7 @@ class QuestionView extends ComponentView { // then the button was clicked, focus on the first tabbable element if (!this.model.get('_isReady')) return; // Attempt to get the current page location - const currentModel = Adapt.findById(Adapt.location._currentId); + const currentModel = data.findById(location._currentId); // Make sure the page is ready if (!currentModel?.get('_isReady')) return; // Focus on the first readable item in this element diff --git a/js/wait.js b/js/wait.js index 9128728a..bc2c8dc1 100644 --- a/js/wait.js +++ b/js/wait.js @@ -1,4 +1,4 @@ -export default class Wait extends Backbone.Controller { +class Wait extends Backbone.Controller { initialize() { this._waitCount = 0; @@ -90,3 +90,7 @@ export default class Wait extends Backbone.Controller { } } + +const wait = new Wait(); + +export default wait; diff --git a/required/adapt/js/scriptLoader.js b/required/adapt/js/scriptLoader.js index cab13249..819e1a41 100644 --- a/required/adapt/js/scriptLoader.js +++ b/required/adapt/js/scriptLoader.js @@ -2,45 +2,6 @@ const isProduction = (window.ADAPT_BUILD_TYPE !== 'development'); - // Change location of Adapt CSS if incorrect - (function () { - const oldHRef = 'adapt/css/adapt.css'; - const newHRef = 'adapt.css'; - function fixCSSLocation() { - const oldLinkElement = findOldLink(); - if (!oldLinkElement) return; - replaceOldLink(oldLinkElement); - } - function findOldLink() { - const nodeList = document.querySelectorAll('link'); - for (let i = 0, l = nodeList.length; i < l; i++) { - const linkElement = nodeList[i]; - if (linkElement.href.substr(-oldHRef.length) !== oldHRef) continue; - return linkElement; - } - } - /** - * replace link tag, otherwise issues with Google Chrome sourcemaps - */ - function replaceOldLink(oldLinkElement) { - console.warn('WARN: DEPRECATED - CSS location needs updating from', oldHRef, 'to', newHRef); - const parent = oldLinkElement.parentNode; - parent.removeChild(oldLinkElement); - const newLinkElement = document.createElement('link'); - newLinkElement.href = newHRef; - newLinkElement.rel = 'stylesheet'; - parent.appendChild(newLinkElement); - } - /** - * wait for document to load otherwise link tag isn't available - */ - if (!document.body) { - document.addEventListener('DOMContentLoaded', fixCSSLocation); - } else { - fixCSSLocation(); - } - })(); - function loadScript(url, callback) { if (!url || typeof url !== 'string') return; const script = document.createElement('script'); diff --git a/templates/header.jsx b/templates/header.jsx index 276087a0..171d4978 100644 --- a/templates/header.jsx +++ b/templates/header.jsx @@ -1,4 +1,5 @@ import Adapt from 'core/js/adapt'; +import device from 'core/js/device'; import React, { useRef } from 'react'; import { prefixClasses, compile } from 'core/js/reactHelpers'; @@ -32,7 +33,7 @@ export default function Header(props) { _component && _component.toLowerCase() ].filter(Boolean) } = props; - const sizedInstruction = (mobileInstruction && Adapt.device.screenSize !== 'large') ? + const sizedInstruction = (mobileInstruction && device.screenSize !== 'large') ? mobileInstruction : instruction; const isSet = (displayTitle || body || sizedInstruction); diff --git a/templates/image.jsx b/templates/image.jsx index fcd72ed4..ccaec0a0 100644 --- a/templates/image.jsx +++ b/templates/image.jsx @@ -1,4 +1,5 @@ -import Adapt from 'core/js/adapt'; +import device from 'core/js/device'; +import a11y from 'core/js/a11y'; import React from 'react'; import { html, classes, prefixClasses } from 'core/js/reactHelpers'; @@ -11,8 +12,8 @@ import { html, classes, prefixClasses } from 'core/js/reactHelpers'; export default function Image(props) { const hasMediumSetting = (Object.prototype.hasOwnProperty.call(props, '_medium') || Object.prototype.hasOwnProperty.call(props, 'medium')); const screenSize = hasMediumSetting - ? Adapt.device.screenSize - : (Adapt.device.screenSize === 'large' ? 'large' : 'small'); + ? device.screenSize + : (device.screenSize === 'large' ? 'large' : 'small'); const src = ( props[`_${screenSize}`] || props[`${screenSize}`] || @@ -31,7 +32,7 @@ export default function Image(props) { From a74ec9e36e28668b6ebf837602483366dad24418 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 23 Mar 2022 14:12:54 +0000 Subject: [PATCH 03/13] issue/2799 Added location jsdocs --- js/location.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/js/location.js b/js/location.js index 31926861..da75dd91 100644 --- a/js/location.js +++ b/js/location.js @@ -4,6 +4,64 @@ import logging from 'core/js/logging'; class Location extends Backbone.Controller { + initialize() { + /** + * _id of previous contentobject + * @type {string} + */ + this._previousId = null; + /** + * _type of previous contentobject + * @type {string} + */ + this._previousContentType = null; + /** + * Model of previous contentobject + * @type {Backbone.Model} + */ + this._previousModel = null; + /** + * _htmlClasses of previous contentobject + * @type {string} + */ + this._previousClasses = null; + /** + * Alias for _previousContentType + * @type {string} + */ + this._lastVisitedType = null; + /** + * _id of last menu + * @type {string} + * */ + this._lastVisitedMenu = null; + /** + * _id of last page + * @type {string} + * */ + this._lastVisitedPage = null; + /** + * _id of current contentobject + * @type {string} + */ + this._currentId = null; + /** + * Model of current contentobject + * @type {Backbone.Model} + */ + this._currentModel = null; + /** + * Current url querystring + * @type {string} + */ + this._currentLocation = null; + /** + * Current contentobject type + * @type {string} + */ + this._contentType = null; + } + } const location = new Location(); From 739b5188958e53b9d3f5c16c10b152c73b2e5672 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 23 Mar 2022 14:30:19 +0000 Subject: [PATCH 04/13] issue/2799 Comment fixes --- js/adapt.js | 10 ++++++++++ js/router.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/js/adapt.js b/js/adapt.js index 86e035f7..8bdd58b8 100644 --- a/js/adapt.js +++ b/js/adapt.js @@ -209,11 +209,21 @@ class AdaptSingleton extends LockingModel { */ get scrolling() {} + /** + * @deprecated Please use core/js/startController instead + */ + get startController() {} + /** * @deprecated Please use core/js/components instead */ get store() {} + /** + * @deprecated Please use core/js/tracking instead + */ + get tracking() {} + /** * @deprecated Please use core/js/wait instead */ diff --git a/js/router.js b/js/router.js index 4ec2e5be..194ec2b7 100644 --- a/js/router.js +++ b/js/router.js @@ -439,7 +439,7 @@ Object.defineProperties(Adapt, { }, router: { get() { - logging.deprecated('router, please use core/js/router directly'); + logging.deprecated('Adapt.router, please use core/js/router directly'); return router; } } From 9c7871a35aa52f5523089e6ac01add472a177600 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:28:35 +0100 Subject: [PATCH 05/13] Update js/adapt.js --- js/adapt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/adapt.js b/js/adapt.js index 8bdd58b8..20084cd3 100644 --- a/js/adapt.js +++ b/js/adapt.js @@ -251,7 +251,7 @@ class AdaptSingleton extends LockingModel { /** * Used to register models and views with `store` - * @deprecated Please use store.register instead. + * @deprecated Please use components.register instead. * @param {string|Array} name The name(s) of the model/view to be registered * @param {object} object Object containing properties `model` and `view` or (legacy) an object representing the view */ From 3956db6e8dbfe4382cc0e90f6c106aafa0832413 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:28:42 +0100 Subject: [PATCH 06/13] Update js/adapt.js --- js/adapt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/adapt.js b/js/adapt.js index 20084cd3..5da490e4 100644 --- a/js/adapt.js +++ b/js/adapt.js @@ -259,7 +259,7 @@ class AdaptSingleton extends LockingModel { /** * Parses a view class name. - * @deprecated Please use store.getViewName instead. + * @deprecated Please use components.getViewName instead. * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data */ getViewName() {} From bc53416290219eb2e5c0a5f4eb9b2d63f85fd5fb Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:28:47 +0100 Subject: [PATCH 07/13] Update js/adapt.js --- js/adapt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/adapt.js b/js/adapt.js index 5da490e4..c5685d30 100644 --- a/js/adapt.js +++ b/js/adapt.js @@ -266,7 +266,7 @@ class AdaptSingleton extends LockingModel { /** * Fetches a view class from the store. For a usage example, see either HotGraphic or Narrative - * @deprecated Please use store.getViewClass instead. + * @deprecated Please use components.getViewClass instead. * @param {string|Backbone.Model|Backbone.View|object} nameModelViewOrData The name of the view class you want to fetch e.g. `"hotgraphic"` or its model or its json data * @returns {Backbone.View} Reference to the view class */ From 23bc439dd2cadc1e828167b34d939f05c687efde Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:28:52 +0100 Subject: [PATCH 08/13] Update js/adapt.js --- js/adapt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/adapt.js b/js/adapt.js index c5685d30..7854d25e 100644 --- a/js/adapt.js +++ b/js/adapt.js @@ -274,7 +274,7 @@ class AdaptSingleton extends LockingModel { /** * Parses a model class name. - * @deprecated Please use store.getModelName instead. + * @deprecated Please use components.getModelName instead. * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"`, the model to process or its json data */ getModelName() {} From fa7587e7dbcb24d459dadb6a1822dab6547e14df Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:28:56 +0100 Subject: [PATCH 09/13] Update js/adapt.js --- js/adapt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/adapt.js b/js/adapt.js index 7854d25e..12a610b9 100644 --- a/js/adapt.js +++ b/js/adapt.js @@ -281,7 +281,7 @@ class AdaptSingleton extends LockingModel { /** * Fetches a model class from the store. For a usage example, see either HotGraphic or Narrative - * @deprecated Please use store.getModelClass instead. + * @deprecated Please use components.getModelClass instead. * @param {string|Backbone.Model|object} name The name of the model you want to fetch e.g. `"hotgraphic"` or its json data * @returns {Backbone.Model} Reference to the view class */ From 7a1ad34756fd5d28af41b9751b36a0836969a69d Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:29:01 +0100 Subject: [PATCH 10/13] Update js/components.js --- js/components.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components.js b/js/components.js index 904ddd3d..ee673645 100644 --- a/js/components.js +++ b/js/components.js @@ -9,7 +9,7 @@ class Components extends Backbone.Controller { } /** - * Used to register models and views with `Adapt.store` + * Used to register models and views * @param {string|Array} name The name(s) of the model/view to be registered * @param {object} object Object containing properties `model` and `view` or (legacy) an object representing the view */ From d142a06a686187c08b951be585b3353de37cce03 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:30:38 +0100 Subject: [PATCH 11/13] Update js/data.js --- js/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/data.js b/js/data.js index b8b5a7ad..2669a5d4 100644 --- a/js/data.js +++ b/js/data.js @@ -286,7 +286,7 @@ Object.defineProperties(Adapt, { }, findViewByModelId: { get() { - logging.deprecated('Adapt.findViewByModelId, data.findViewByModelId directly'); + logging.deprecated('Adapt.findViewByModelId, please use data.findViewByModelId directly'); return data.findViewByModelId; } }, From 1ef2a330552cddfa8ec5f87e85b277a72a5df75a Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 30 Mar 2022 10:30:43 +0100 Subject: [PATCH 12/13] Update js/components.js --- js/components.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components.js b/js/components.js index ee673645..35ef3946 100644 --- a/js/components.js +++ b/js/components.js @@ -186,7 +186,7 @@ Object.defineProperties(Adapt, { }, register: { get() { - logging.deprecated('components.register, please use components.register instead'); + logging.deprecated('Adapt.register, please use components.register instead'); return components.register; } }, From e4013b12c5f411163c2029a37388aed1d8aad267 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Mon, 4 Apr 2022 10:42:35 +0100 Subject: [PATCH 13/13] issue/2779 Updated warning output --- js/logging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/logging.js b/js/logging.js index 3236424a..953e360b 100644 --- a/js/logging.js +++ b/js/logging.js @@ -137,7 +137,7 @@ const logging = new Logging(); Object.defineProperty(Adapt, 'log', { get() { - logging.deprecated('logging, please use core/js/logging directly'); + logging.deprecated('Adapt.log, please use core/js/logging directly'); return logging; } });