diff options
Diffstat (limited to 'core/modules/contextual/js')
-rw-r--r-- | core/modules/contextual/js/contextual.js | 254 | ||||
-rw-r--r-- | core/modules/contextual/js/contextualModelView.js | 254 |
2 files changed, 253 insertions, 255 deletions
diff --git a/core/modules/contextual/js/contextual.js b/core/modules/contextual/js/contextual.js index f1008eabe07b..5a852e28fbac 100644 --- a/core/modules/contextual/js/contextual.js +++ b/core/modules/contextual/js/contextual.js @@ -256,7 +256,259 @@ } }, }), - ContextualModelView: {}, + + /** + * Models the state of a contextual link's trigger, list & region. + */ + ContextualModelView: class { + constructor($contextual, $region, options) { + this.title = options.title || ''; + this.regionIsHovered = false; + this._hasFocus = false; + this._isOpen = false; + this._isLocked = false; + this.strings = options.strings; + this.timer = NaN; + this.modelId = btoa(Math.random()).substring(0, 12); + this.$region = $region; + this.$contextual = $contextual; + + if (!document.body.classList.contains('touchevents')) { + this.$region.on({ + mouseenter: () => { + this.regionIsHovered = true; + }, + mouseleave: () => { + this.close().blur(); + this.regionIsHovered = false; + }, + 'mouseleave mouseenter': () => this.render(), + }); + this.$contextual.on('mouseenter', () => { + this.focus(); + this.render(); + }); + } + + this.$contextual.on( + { + click: () => { + this.toggleOpen(); + }, + touchend: () => { + Drupal.contextual.ContextualModelView.touchEndToClick(); + }, + focus: () => { + this.focus(); + }, + blur: () => { + this.blur(); + }, + 'click blur touchend focus': () => this.render(), + }, + '.trigger', + ); + + this.$contextual.on( + { + click: () => { + this.close().blur(); + }, + touchend: (event) => { + Drupal.contextual.ContextualModelView.touchEndToClick(event); + }, + focus: () => { + this.focus(); + }, + blur: () => { + this.waitCloseThenBlur(); + }, + 'click blur touchend focus': () => this.render(), + }, + '.contextual-links a', + ); + + this.render(); + + // Let other JavaScript react to the adding of a new contextual link. + $(document).trigger('drupalContextualLinkAdded', { + $el: $contextual, + $region, + model: this, + }); + } + + /** + * Updates the rendered representation of the current contextual links. + */ + render() { + const { isOpen } = this; + const isVisible = this.isLocked || this.regionIsHovered || isOpen; + this.$region.toggleClass('focus', this.hasFocus); + this.$contextual + .toggleClass('open', isOpen) + // Update the visibility of the trigger. + .find('.trigger') + .toggleClass('visually-hidden', !isVisible); + + this.$contextual.find('.contextual-links').prop('hidden', !isOpen); + const trigger = this.$contextual.find('.trigger').get(0); + trigger.textContent = Drupal.t('@action @title configuration options', { + '@action': !isOpen ? this.strings.open : this.strings.close, + '@title': this.title, + }); + trigger.setAttribute('aria-pressed', isOpen); + } + + /** + * Prevents delay and simulated mouse events. + * + * @param {jQuery.Event} event the touch end event. + */ + static touchEndToClick(event) { + event.preventDefault(); + event.target.click(); + } + + /** + * Set up a timeout to allow a user to tab between the trigger and the + * contextual links without the menu dismissing. + */ + waitCloseThenBlur() { + this.timer = window.setTimeout(() => { + this.isOpen = false; + this.hasFocus = false; + this.render(); + }, 150); + } + + /** + * Opens or closes the contextual link. + * + * If it is opened, then also give focus. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + toggleOpen() { + const newIsOpen = !this.isOpen; + this.isOpen = newIsOpen; + if (newIsOpen) { + this.focus(); + } + return this; + } + + /** + * Gives focus to this contextual link. + * + * Also closes + removes focus from every other contextual link. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + focus() { + const { modelId } = this; + Drupal.contextual.instances.forEach((model) => { + if (model.modelId !== modelId) { + model.close().blur(); + } + }); + window.clearTimeout(this.timer); + this.hasFocus = true; + return this; + } + + /** + * Removes focus from this contextual link, unless it is open. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + blur() { + if (!this.isOpen) { + this.hasFocus = false; + } + return this; + } + + /** + * Closes this contextual link. + * + * Does not call blur() because we want to allow a contextual link to have + * focus, yet be closed for example when hovering. + * + * @return {Drupal.contextual.ContextualModelView} + * The current contextual model view. + */ + close() { + this.isOpen = false; + return this; + } + + /** + * Gets the current focus state. + * + * @return {boolean} the focus state. + */ + get hasFocus() { + return this._hasFocus; + } + + /** + * Sets the current focus state. + * + * @param {boolean} value - new focus state + */ + set hasFocus(value) { + this._hasFocus = value; + this.$region.toggleClass('focus', this._hasFocus); + } + + /** + * Gets the current open state. + * + * @return {boolean} the open state. + */ + get isOpen() { + return this._isOpen; + } + + /** + * Sets the current open state. + * + * @param {boolean} value - new open state + */ + set isOpen(value) { + this._isOpen = value; + // Nested contextual region handling: hide any nested contextual triggers. + this.$region + .closest('.contextual-region') + .find('.contextual .trigger:not(:first)') + .toggle(!this.isOpen); + } + + /** + * Gets the current locked state. + * + * @return {boolean} the locked state. + */ + get isLocked() { + return this._isLocked; + } + + /** + * Sets the current locked state. + * + * @param {boolean} value - new locked state + */ + set isLocked(value) { + if (value !== this._isLocked) { + this._isLocked = value; + this.render(); + } + } + }, }; /** diff --git a/core/modules/contextual/js/contextualModelView.js b/core/modules/contextual/js/contextualModelView.js deleted file mode 100644 index 4488045e2236..000000000000 --- a/core/modules/contextual/js/contextualModelView.js +++ /dev/null @@ -1,254 +0,0 @@ -(($, Drupal) => { - /** - * Models the state of a contextual link's trigger, list & region. - */ - Drupal.contextual.ContextualModelView = class { - constructor($contextual, $region, options) { - this.title = options.title || ''; - this.regionIsHovered = false; - this._hasFocus = false; - this._isOpen = false; - this._isLocked = false; - this.strings = options.strings; - this.timer = NaN; - this.modelId = btoa(Math.random()).substring(0, 12); - this.$region = $region; - this.$contextual = $contextual; - - if (!document.body.classList.contains('touchevents')) { - this.$region.on({ - mouseenter: () => { - this.regionIsHovered = true; - }, - mouseleave: () => { - this.close().blur(); - this.regionIsHovered = false; - }, - 'mouseleave mouseenter': () => this.render(), - }); - this.$contextual.on('mouseenter', () => { - this.focus(); - this.render(); - }); - } - - this.$contextual.on( - { - click: () => { - this.toggleOpen(); - }, - touchend: () => { - Drupal.contextual.ContextualModelView.touchEndToClick(); - }, - focus: () => { - this.focus(); - }, - blur: () => { - this.blur(); - }, - 'click blur touchend focus': () => this.render(), - }, - '.trigger', - ); - - this.$contextual.on( - { - click: () => { - this.close().blur(); - }, - touchend: (event) => { - Drupal.contextual.ContextualModelView.touchEndToClick(event); - }, - focus: () => { - this.focus(); - }, - blur: () => { - this.waitCloseThenBlur(); - }, - 'click blur touchend focus': () => this.render(), - }, - '.contextual-links a', - ); - - this.render(); - - // Let other JavaScript react to the adding of a new contextual link. - $(document).trigger('drupalContextualLinkAdded', { - $el: $contextual, - $region, - model: this, - }); - } - - /** - * Updates the rendered representation of the current contextual links. - */ - render() { - const { isOpen } = this; - const isVisible = this.isLocked || this.regionIsHovered || isOpen; - this.$region.toggleClass('focus', this.hasFocus); - this.$contextual - .toggleClass('open', isOpen) - // Update the visibility of the trigger. - .find('.trigger') - .toggleClass('visually-hidden', !isVisible); - - this.$contextual.find('.contextual-links').prop('hidden', !isOpen); - const trigger = this.$contextual.find('.trigger').get(0); - trigger.textContent = Drupal.t('@action @title configuration options', { - '@action': !isOpen ? this.strings.open : this.strings.close, - '@title': this.title, - }); - trigger.setAttribute('aria-pressed', isOpen); - } - - /** - * Prevents delay and simulated mouse events. - * - * @param {jQuery.Event} event the touch end event. - */ - static touchEndToClick(event) { - event.preventDefault(); - event.target.click(); - } - - /** - * Set up a timeout to allow a user to tab between the trigger and the - * contextual links without the menu dismissing. - */ - waitCloseThenBlur() { - this.timer = window.setTimeout(() => { - this.isOpen = false; - this.hasFocus = false; - this.render(); - }, 150); - } - - /** - * Opens or closes the contextual link. - * - * If it is opened, then also give focus. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - toggleOpen() { - const newIsOpen = !this.isOpen; - this.isOpen = newIsOpen; - if (newIsOpen) { - this.focus(); - } - return this; - } - - /** - * Gives focus to this contextual link. - * - * Also closes + removes focus from every other contextual link. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - focus() { - const { modelId } = this; - Drupal.contextual.instances.forEach((model) => { - if (model.modelId !== modelId) { - model.close().blur(); - } - }); - window.clearTimeout(this.timer); - this.hasFocus = true; - return this; - } - - /** - * Removes focus from this contextual link, unless it is open. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - blur() { - if (!this.isOpen) { - this.hasFocus = false; - } - return this; - } - - /** - * Closes this contextual link. - * - * Does not call blur() because we want to allow a contextual link to have - * focus, yet be closed for example when hovering. - * - * @return {Drupal.contextual.ContextualModelView} - * The current contextual model view. - */ - close() { - this.isOpen = false; - return this; - } - - /** - * Gets the current focus state. - * - * @return {boolean} the focus state. - */ - get hasFocus() { - return this._hasFocus; - } - - /** - * Sets the current focus state. - * - * @param {boolean} value - new focus state - */ - set hasFocus(value) { - this._hasFocus = value; - this.$region.toggleClass('focus', this._hasFocus); - } - - /** - * Gets the current open state. - * - * @return {boolean} the open state. - */ - get isOpen() { - return this._isOpen; - } - - /** - * Sets the current open state. - * - * @param {boolean} value - new open state - */ - set isOpen(value) { - this._isOpen = value; - // Nested contextual region handling: hide any nested contextual triggers. - this.$region - .closest('.contextual-region') - .find('.contextual .trigger:not(:first)') - .toggle(!this.isOpen); - } - - /** - * Gets the current locked state. - * - * @return {boolean} the locked state. - */ - get isLocked() { - return this._isLocked; - } - - /** - * Sets the current locked state. - * - * @param {boolean} value - new locked state - */ - set isLocked(value) { - if (value !== this._isLocked) { - this._isLocked = value; - this.render(); - } - } - }; -})(jQuery, Drupal); |