From ef37f002ee3189cbe647a853d287eb4e5e1b0fba Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Wed, 23 May 2018 10:04:22 +0000 Subject: Once upon a midnight dreary, while I coded, weak and weary, In many a strange and curious file of forgotten lore— While I pondered, blaming Nacin, my notifications suddenly awakened, As of someone quietly DMing;—DMing me, I can’t ignore. “’Tis some contributor,” I muttered, “DMing me an idea or four— Only this and nothing more.” MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ah, distinctly I remember, at WordCamp US, last December; A mad proposal nearly laid me—down out cold—upon the floor. Curious, I listened closely;—to a plan I agreed with, mostly— A way to make our JavaScript—JavaScript which was a chore— Maintainable, extendable, for the future, is what I saw. Guten-ready for evermore. Open here I switch to Slack, when, with many a patch and hack, In there stepped Omar, a JavaScript developer hardcore; Pronouncing all the changes fit; ready now to be commit; “There’s nothing else for us to do,” DMing me, “It’s done!” he swore— “No longer random guessing at which file need next be explored— Let’s move on, we’re all aboard.” Moved all together, grouped and managed, in folders all is packaged, The code had all been cleaned and tidied, important parts moved to the fore, “Though this change be useful here,” I said, “it is too large, I fear, We couldn’t manage such a patch, we’ve done nothing like this before— Tell me where doth go this change, change to make our codebase soar!” Quoth Omar, “In WordPress Core.” Props omarreis for shepherding this significant change. Props adamsilverstein, aduth, atimmer, dingo_bastard, frank-klein, gziolo, herregroen, jaswrks, jeremyfelt, jipmoors, jorbin, netweb, ocean90, pento, tjnowell, and youknowriad for testing, feedback, discussion, encouragement, commiserations, etc. I make no apologies for this commit message. Fixes #43055. git-svn-id: https://develop.svn.wordpress.org/trunk@43309 602fd350-edb4-49c9-b593-d223f7449a82 --- src/js/_enqueues/lib/pointer.js | 285 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 src/js/_enqueues/lib/pointer.js (limited to 'src/js/_enqueues/lib/pointer.js') diff --git a/src/js/_enqueues/lib/pointer.js b/src/js/_enqueues/lib/pointer.js new file mode 100644 index 0000000000..a6b13c7fa5 --- /dev/null +++ b/src/js/_enqueues/lib/pointer.js @@ -0,0 +1,285 @@ +/* global wpPointerL10n */ +/** + * Pointer jQuery widget. + */ +(function($){ + var identifier = 0, + zindex = 9999; + + /** + * @class $.widget.wp.pointer + */ + $.widget('wp.pointer',/** @lends $.widget.wp.pointer.prototype */{ + options: { + pointerClass: 'wp-pointer', + pointerWidth: 320, + content: function() { + return $(this).text(); + }, + buttons: function( event, t ) { + var close = ( wpPointerL10n ) ? wpPointerL10n.dismiss : 'Dismiss', + button = $('' + close + ''); + + return button.bind( 'click.pointer', function(e) { + e.preventDefault(); + t.element.pointer('close'); + }); + }, + position: 'top', + show: function( event, t ) { + t.pointer.show(); + t.opened(); + }, + hide: function( event, t ) { + t.pointer.hide(); + t.closed(); + }, + document: document + }, + + _create: function() { + var positioning, + family; + + this.content = $('
'); + this.arrow = $('
'); + + family = this.element.parents().add( this.element ); + positioning = 'absolute'; + + if ( family.filter(function(){ return 'fixed' === $(this).css('position'); }).length ) + positioning = 'fixed'; + + this.pointer = $('
') + .append( this.content ) + .append( this.arrow ) + .attr('id', 'wp-pointer-' + identifier++) + .addClass( this.options.pointerClass ) + .css({'position': positioning, 'width': this.options.pointerWidth+'px', 'display': 'none'}) + .appendTo( this.options.document.body ); + }, + + _setOption: function( key, value ) { + var o = this.options, + tip = this.pointer; + + // Handle document transfer + if ( key === 'document' && value !== o.document ) { + tip.detach().appendTo( value.body ); + + // Handle class change + } else if ( key === 'pointerClass' ) { + tip.removeClass( o.pointerClass ).addClass( value ); + } + + // Call super method. + $.Widget.prototype._setOption.apply( this, arguments ); + + // Reposition automatically + if ( key === 'position' ) { + this.reposition(); + + // Update content automatically if pointer is open + } else if ( key === 'content' && this.active ) { + this.update(); + } + }, + + destroy: function() { + this.pointer.remove(); + $.Widget.prototype.destroy.call( this ); + }, + + widget: function() { + return this.pointer; + }, + + update: function( event ) { + var self = this, + o = this.options, + dfd = $.Deferred(), + content; + + if ( o.disabled ) + return; + + dfd.done( function( content ) { + self._update( event, content ); + }); + + // Either o.content is a string... + if ( typeof o.content === 'string' ) { + content = o.content; + + // ...or o.content is a callback. + } else { + content = o.content.call( this.element[0], dfd.resolve, event, this._handoff() ); + } + + // If content is set, then complete the update. + if ( content ) + dfd.resolve( content ); + + return dfd.promise(); + }, + + /** + * Update is separated into two functions to allow events to defer + * updating the pointer (e.g. fetch content with ajax, etc). + */ + _update: function( event, content ) { + var buttons, + o = this.options; + + if ( ! content ) + return; + + this.pointer.stop(); // Kill any animations on the pointer. + this.content.html( content ); + + buttons = o.buttons.call( this.element[0], event, this._handoff() ); + if ( buttons ) { + buttons.wrap('
').parent().appendTo( this.content ); + } + + this.reposition(); + }, + + reposition: function() { + var position; + + if ( this.options.disabled ) + return; + + position = this._processPosition( this.options.position ); + + // Reposition pointer. + this.pointer.css({ + top: 0, + left: 0, + zIndex: zindex++ // Increment the z-index so that it shows above other opened pointers. + }).show().position($.extend({ + of: this.element, + collision: 'fit none' + }, position )); // the object comes before this.options.position so the user can override position.of. + + this.repoint(); + }, + + repoint: function() { + var o = this.options, + edge; + + if ( o.disabled ) + return; + + edge = ( typeof o.position == 'string' ) ? o.position : o.position.edge; + + // Remove arrow classes. + this.pointer[0].className = this.pointer[0].className.replace( /wp-pointer-[^\s'"]*/, '' ); + + // Add arrow class. + this.pointer.addClass( 'wp-pointer-' + edge ); + }, + + _processPosition: function( position ) { + var opposite = { + top: 'bottom', + bottom: 'top', + left: 'right', + right: 'left' + }, + result; + + // If the position object is a string, it is shorthand for position.edge. + if ( typeof position == 'string' ) { + result = { + edge: position + '' + }; + } else { + result = $.extend( {}, position ); + } + + if ( ! result.edge ) + return result; + + if ( result.edge == 'top' || result.edge == 'bottom' ) { + result.align = result.align || 'left'; + + result.at = result.at || result.align + ' ' + opposite[ result.edge ]; + result.my = result.my || result.align + ' ' + result.edge; + } else { + result.align = result.align || 'top'; + + result.at = result.at || opposite[ result.edge ] + ' ' + result.align; + result.my = result.my || result.edge + ' ' + result.align; + } + + return result; + }, + + open: function( event ) { + var self = this, + o = this.options; + + if ( this.active || o.disabled || this.element.is(':hidden') ) + return; + + this.update().done( function() { + self._open( event ); + }); + }, + + _open: function( event ) { + var self = this, + o = this.options; + + if ( this.active || o.disabled || this.element.is(':hidden') ) + return; + + this.active = true; + + this._trigger( 'open', event, this._handoff() ); + + this._trigger( 'show', event, this._handoff({ + opened: function() { + self._trigger( 'opened', event, self._handoff() ); + } + })); + }, + + close: function( event ) { + if ( !this.active || this.options.disabled ) + return; + + var self = this; + this.active = false; + + this._trigger( 'close', event, this._handoff() ); + this._trigger( 'hide', event, this._handoff({ + closed: function() { + self._trigger( 'closed', event, self._handoff() ); + } + })); + }, + + sendToTop: function() { + if ( this.active ) + this.pointer.css( 'z-index', zindex++ ); + }, + + toggle: function( event ) { + if ( this.pointer.is(':hidden') ) + this.open( event ); + else + this.close( event ); + }, + + _handoff: function( extend ) { + return $.extend({ + pointer: this.pointer, + element: this.element + }, extend); + } + }); +})(jQuery); -- cgit v1.2.3