░▒▓████████████████████████████████▓▒░ ░▒▓█ ▓▒░ ░▒▓█ ~ S W A M P ~ ▓▒░ ░▒▓█ ▓▒░ ░▒▓████████████████████████████████▓▒░
pplmvsvm
LOCATION:
/var/www/canvas/packages/jquery-popover
☗ ROOT
↻ REFRESH
✎ CARVE FLESH
EDITING: index.js
// // Copyright (C) 2012 - present Instructure, Inc. // // This file is part of Canvas. // // Canvas is free software: you can redistribute it and/or modify it under // the terms of the GNU Affero General Public License as published by the Free // Software Foundation, version 3 of the License. // // Canvas is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. See the GNU Affero General Public License for more // details. // // You should have received a copy of the GNU Affero General Public License along // with this program. If not, see <http://www.gnu.org/licenses/>. import $ from 'jquery' // you can provide a 'using' option to jqueryUI position // it will be passed the position cordinates and a feedback object which, // among other things, tells you where it positioned it relative to the target. we use it to add some // css classes that handle putting the pointer triangle (aka: caret) back to the trigger. function using(position, feedback) { if (position.top < 0) position.top = 0 return $(this) .css(position) .toggleClass('carat-bottom', feedback.vertical === 'bottom') } let idCounter = 0 const activePopovers = [] function trapFocus(element) { const focusableEls = element.querySelectorAll( 'a[href], button, textarea, input[type="text"], input[type="radio"], input[type="checkbox"], select' ) const firstFocusableEl = focusableEls[0] const lastFocusableEl = focusableEls[focusableEls.length - 1] const KEYCODE_TAB = 9 element.addEventListener('keydown', e => { const isTabPressed = e.key === 'Tab' || e.keyCode === KEYCODE_TAB if (!isTabPressed) { return } if (e.shiftKey) { /* shift + tab */ if (document.activeElement === firstFocusableEl) { lastFocusableEl.focus() e.preventDefault() } } /* tab */ else if (document.activeElement === lastFocusableEl) { setTimeout(() => { firstFocusableEl.focus() }) e.preventDefault() } }) } export default class Popover { ignoreOutsideClickSelector = '.ui-dialog' constructor(triggerEvent, content, options = {}) { this.content = content this.options = options this.trigger = $(triggerEvent.currentTarget) this.triggerAction = triggerEvent.type this.focusTrapped = false this.el = $(this.content) .addClass('carat-bottom') .data('popover', this) .keydown(event => { // if the user hits the escape key, reset the focus to what it was. if (event.keyCode === $.ui.keyCode.ESCAPE) this.hide() // If the user tabs or shift-tabs away, close. if (event.keyCode !== $.ui.keyCode.TAB) return const tabbables = $(':tabbable', this.el) const index = $.inArray(event.target, tabbables) if (index === -1) return if (event.shiftKey) { if (!this.focusTrapped && index === 0) this.hide() } else if (!this.focusTrapped && index === tabbables.length - 1) this.hide() }) this.el.delegate('.popover_close', 'keyclick click', event => { event.preventDefault() this.hide() }) this.show(triggerEvent) } trapFocus(element) { this.focusTrapped = true trapFocus(element) } show(triggerEvent) { // when the popover is open, we don't want SR users to be able to navigate to the flash messages let popoverToHide $.screenReaderFlashMessageExclusive('') while ((popoverToHide = activePopovers.pop())) { popoverToHide.hide() } activePopovers.push(this) const id = `popover-${idCounter++}` this.trigger.attr({ 'aria-expanded': true, 'aria-controls': id }) this.previousTarget = triggerEvent.currentTarget this.el .attr({id}) .appendTo(document.body) .show() this.position() if (triggerEvent.type !== 'mouseenter') { this.el .find(':tabbable') .first() .focus() setTimeout( () => this.el .find(':tabbable') .first() .focus(), 100 ) } document.querySelector('#application').setAttribute('aria-hidden', 'true') // handle sticking the carat right above where you clicked on the button, bounded by the dialog this.el.find('.ui-menu-carat').remove() const additionalOffset = this.options.manualOffset || 0 const differenceInOffset = this.trigger.offset().left - this.el.offset().left const actualOffset = triggerEvent.pageX - this.trigger.offset().left const leftBound = Math.max(0, this.trigger.width() / 2 - this.el.width() / 2) + 20 const rightBound = this.trigger.width() - leftBound const caratOffset = Math.min(Math.max(leftBound, actualOffset), rightBound) + differenceInOffset + additionalOffset $('<span class="ui-menu-carat"><span /></span>') .css('left', caratOffset) .prependTo(this.el) this.positionInterval = setInterval(this.position, 200) $(window).click(this.outsideClickHandler) } hide() { // remove this from the activePopovers array for (let index = 0; index < activePopovers.length; index++) { const popover = activePopovers[index] if (this === popover) { activePopovers.splice(index, 1) } } this.el.detach() this.trigger.attr('aria-expanded', false) clearInterval(this.positionInterval) $(window).unbind('click', this.outsideClickHandler) this.restoreFocus() if (activePopovers.length === 0) { document.querySelector('#application').setAttribute('aria-hidden', 'false') } } // uses a fat arrow so that it has a unique guid per-instance for jquery event unbinding outsideClickHandler = event => { if ( !$(event.target).closest(this.el.add(this.trigger).add(this.ignoreOutsideClickSelector)) .length ) { this.hide() } } position = () => this.el.position({ my: `center ${this.options.verticalSide === 'bottom' ? 'top' : 'bottom'}`, at: `center ${this.options.verticalSide || 'top'}`, of: this.trigger, offset: `0px ${this.offsetPx()}px`, within: 'body', collision: `flipfit ${this.options.verticalSide ? 'none' : 'flipfit'}`, using }) offsetPx() { const offset = this.options.verticalSide === 'bottom' ? 10 : -10 if (this.options.invertOffset) { return offset * -1 } else { return offset } } restoreFocus() { // set focus back to the previously focused item. if (this.previousTarget && $(this.previousTarget).is(':visible')) { this.previousTarget.focus() } } }
CANCEL
Name
Type
Size
Modified
Actions
↩ ..
DIR
—
—
📄 index.js
JS
6.6 KB
2023-09-24 03:36
EDIT
📄 package.json
JSON
116 B
2023-09-24 03:36
EDIT