summaryrefslogtreecommitdiffstatshomepage
path: root/src/js/_enqueues/lib/pointer.js
diff options
context:
space:
mode:
authorGary Pendergast <pento@git.wordpress.org>2018-05-23 10:04:22 +0000
committerGary Pendergast <pento@git.wordpress.org>2018-05-23 10:04:22 +0000
commitef37f002ee3189cbe647a853d287eb4e5e1b0fba (patch)
tree8e37b569f34bd841fd91ffdf40948069db436a16 /src/js/_enqueues/lib/pointer.js
parentacebda9aa553b01e4bdfe8e2b8e30827271aaa05 (diff)
downloadwordpress-ef37f002ee3189cbe647a853d287eb4e5e1b0fba.tar.gz
wordpress-ef37f002ee3189cbe647a853d287eb4e5e1b0fba.zip
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.” 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
Diffstat (limited to 'src/js/_enqueues/lib/pointer.js')
-rw-r--r--src/js/_enqueues/lib/pointer.js285
1 files changed, 285 insertions, 0 deletions
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 = $('<a class="close" href="#">' + close + '</a>');
+
+ 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 = $('<div class="wp-pointer-content"></div>');
+ this.arrow = $('<div class="wp-pointer-arrow"><div class="wp-pointer-arrow-inner"></div></div>');
+
+ family = this.element.parents().add( this.element );
+ positioning = 'absolute';
+
+ if ( family.filter(function(){ return 'fixed' === $(this).css('position'); }).length )
+ positioning = 'fixed';
+
+ this.pointer = $('<div />')
+ .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('<div class="wp-pointer-buttons" />').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);