home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / js / wp-pointer.js < prev    next >
Encoding:
JavaScript  |  2017-09-08  |  6.5 KB  |  286 lines

  1. /* global wpPointerL10n */
  2. /**
  3.  * Pointer jQuery widget.
  4.  */
  5. (function($){
  6.     var identifier = 0,
  7.         zindex = 9999;
  8.  
  9.     /**
  10.      * @class $.widget.wp.pointer
  11.      */
  12.     $.widget('wp.pointer',/** @lends $.widget.wp.pointer.prototype */{
  13.         options: {
  14.             pointerClass: 'wp-pointer',
  15.             pointerWidth: 320,
  16.             content: function() {
  17.                 return $(this).text();
  18.             },
  19.             buttons: function( event, t ) {
  20.                 var close  = ( wpPointerL10n ) ? wpPointerL10n.dismiss : 'Dismiss',
  21.                     button = $('<a class="close" href="#">' + close + '</a>');
  22.  
  23.                 return button.bind( 'click.pointer', function(e) {
  24.                     e.preventDefault();
  25.                     t.element.pointer('close');
  26.                 });
  27.             },
  28.             position: 'top',
  29.             show: function( event, t ) {
  30.                 t.pointer.show();
  31.                 t.opened();
  32.             },
  33.             hide: function( event, t ) {
  34.                 t.pointer.hide();
  35.                 t.closed();
  36.             },
  37.             document: document
  38.         },
  39.  
  40.         _create: function() {
  41.             var positioning,
  42.                 family;
  43.  
  44.             this.content = $('<div class="wp-pointer-content"></div>');
  45.             this.arrow   = $('<div class="wp-pointer-arrow"><div class="wp-pointer-arrow-inner"></div></div>');
  46.  
  47.             family = this.element.parents().add( this.element );
  48.             positioning = 'absolute';
  49.  
  50.             if ( family.filter(function(){ return 'fixed' === $(this).css('position'); }).length )
  51.                 positioning = 'fixed';
  52.  
  53.             this.pointer = $('<div />')
  54.                 .append( this.content )
  55.                 .append( this.arrow )
  56.                 .attr('id', 'wp-pointer-' + identifier++)
  57.                 .addClass( this.options.pointerClass )
  58.                 .css({'position': positioning, 'width': this.options.pointerWidth+'px', 'display': 'none'})
  59.                 .appendTo( this.options.document.body );
  60.         },
  61.  
  62.         _setOption: function( key, value ) {
  63.             var o   = this.options,
  64.                 tip = this.pointer;
  65.  
  66.             // Handle document transfer
  67.             if ( key === 'document' && value !== o.document ) {
  68.                 tip.detach().appendTo( value.body );
  69.  
  70.             // Handle class change
  71.             } else if ( key === 'pointerClass' ) {
  72.                 tip.removeClass( o.pointerClass ).addClass( value );
  73.             }
  74.  
  75.             // Call super method.
  76.             $.Widget.prototype._setOption.apply( this, arguments );
  77.  
  78.             // Reposition automatically
  79.             if ( key === 'position' ) {
  80.                 this.reposition();
  81.  
  82.             // Update content automatically if pointer is open
  83.             } else if ( key === 'content' && this.active ) {
  84.                 this.update();
  85.             }
  86.         },
  87.  
  88.         destroy: function() {
  89.             this.pointer.remove();
  90.             $.Widget.prototype.destroy.call( this );
  91.         },
  92.  
  93.         widget: function() {
  94.             return this.pointer;
  95.         },
  96.  
  97.         update: function( event ) {
  98.             var self = this,
  99.                 o    = this.options,
  100.                 dfd  = $.Deferred(),
  101.                 content;
  102.  
  103.             if ( o.disabled )
  104.                 return;
  105.  
  106.             dfd.done( function( content ) {
  107.                 self._update( event, content );
  108.             });
  109.  
  110.             // Either o.content is a string...
  111.             if ( typeof o.content === 'string' ) {
  112.                 content = o.content;
  113.  
  114.             // ...or o.content is a callback.
  115.             } else {
  116.                 content = o.content.call( this.element[0], dfd.resolve, event, this._handoff() );
  117.             }
  118.  
  119.             // If content is set, then complete the update.
  120.             if ( content )
  121.                 dfd.resolve( content );
  122.  
  123.             return dfd.promise();
  124.         },
  125.  
  126.         /**
  127.          * Update is separated into two functions to allow events to defer
  128.          * updating the pointer (e.g. fetch content with ajax, etc).
  129.          */
  130.         _update: function( event, content ) {
  131.             var buttons,
  132.                 o = this.options;
  133.  
  134.             if ( ! content )
  135.                 return;
  136.  
  137.             this.pointer.stop(); // Kill any animations on the pointer.
  138.             this.content.html( content );
  139.  
  140.             buttons = o.buttons.call( this.element[0], event, this._handoff() );
  141.             if ( buttons ) {
  142.                 buttons.wrap('<div class="wp-pointer-buttons" />').parent().appendTo( this.content );
  143.             }
  144.  
  145.             this.reposition();
  146.         },
  147.  
  148.         reposition: function() {
  149.             var position;
  150.  
  151.             if ( this.options.disabled )
  152.                 return;
  153.  
  154.             position = this._processPosition( this.options.position );
  155.  
  156.             // Reposition pointer.
  157.             this.pointer.css({
  158.                 top: 0,
  159.                 left: 0,
  160.                 zIndex: zindex++ // Increment the z-index so that it shows above other opened pointers.
  161.             }).show().position($.extend({
  162.                 of: this.element,
  163.                 collision: 'fit none'
  164.             }, position )); // the object comes before this.options.position so the user can override position.of.
  165.  
  166.             this.repoint();
  167.         },
  168.  
  169.         repoint: function() {
  170.             var o = this.options,
  171.                 edge;
  172.  
  173.             if ( o.disabled )
  174.                 return;
  175.  
  176.             edge = ( typeof o.position == 'string' ) ? o.position : o.position.edge;
  177.  
  178.             // Remove arrow classes.
  179.             this.pointer[0].className = this.pointer[0].className.replace( /wp-pointer-[^\s'"]*/, '' );
  180.  
  181.             // Add arrow class.
  182.             this.pointer.addClass( 'wp-pointer-' + edge );
  183.         },
  184.  
  185.         _processPosition: function( position ) {
  186.             var opposite = {
  187.                     top: 'bottom',
  188.                     bottom: 'top',
  189.                     left: 'right',
  190.                     right: 'left'
  191.                 },
  192.                 result;
  193.  
  194.             // If the position object is a string, it is shorthand for position.edge.
  195.             if ( typeof position == 'string' ) {
  196.                 result = {
  197.                     edge: position + ''
  198.                 };
  199.             } else {
  200.                 result = $.extend( {}, position );
  201.             }
  202.  
  203.             if ( ! result.edge )
  204.                 return result;
  205.  
  206.             if ( result.edge == 'top' || result.edge == 'bottom' ) {
  207.                 result.align = result.align || 'left';
  208.  
  209.                 result.at = result.at || result.align + ' ' + opposite[ result.edge ];
  210.                 result.my = result.my || result.align + ' ' + result.edge;
  211.             } else {
  212.                 result.align = result.align || 'top';
  213.  
  214.                 result.at = result.at || opposite[ result.edge ] + ' ' + result.align;
  215.                 result.my = result.my || result.edge + ' ' + result.align;
  216.             }
  217.  
  218.             return result;
  219.         },
  220.  
  221.         open: function( event ) {
  222.             var self = this,
  223.                 o    = this.options;
  224.  
  225.             if ( this.active || o.disabled || this.element.is(':hidden') )
  226.                 return;
  227.  
  228.             this.update().done( function() {
  229.                 self._open( event );
  230.             });
  231.         },
  232.  
  233.         _open: function( event ) {
  234.             var self = this,
  235.                 o    = this.options;
  236.  
  237.             if ( this.active || o.disabled || this.element.is(':hidden') )
  238.                 return;
  239.  
  240.             this.active = true;
  241.  
  242.             this._trigger( 'open', event, this._handoff() );
  243.  
  244.             this._trigger( 'show', event, this._handoff({
  245.                 opened: function() {
  246.                     self._trigger( 'opened', event, self._handoff() );
  247.                 }
  248.             }));
  249.         },
  250.  
  251.         close: function( event ) {
  252.             if ( !this.active || this.options.disabled )
  253.                 return;
  254.  
  255.             var self = this;
  256.             this.active = false;
  257.  
  258.             this._trigger( 'close', event, this._handoff() );
  259.             this._trigger( 'hide', event, this._handoff({
  260.                 closed: function() {
  261.                     self._trigger( 'closed', event, self._handoff() );
  262.                 }
  263.             }));
  264.         },
  265.  
  266.         sendToTop: function() {
  267.             if ( this.active )
  268.                 this.pointer.css( 'z-index', zindex++ );
  269.         },
  270.  
  271.         toggle: function( event ) {
  272.             if ( this.pointer.is(':hidden') )
  273.                 this.open( event );
  274.             else
  275.                 this.close( event );
  276.         },
  277.  
  278.         _handoff: function( extend ) {
  279.             return $.extend({
  280.                 pointer: this.pointer,
  281.                 element: this.element
  282.             }, extend);
  283.         }
  284.     });
  285. })(jQuery);
  286.