~canonical-sysadmins/wordpress/4.7.4

« back to all changes in this revision

Viewing changes to wp-includes/js/wp-pointer.js

  • Committer: Jacek Nykis
  • Date: 2015-01-05 16:17:05 UTC
  • Revision ID: jacek.nykis@canonical.com-20150105161705-w544l1h5mcg7u4w9
Initial commit

Show diffs side-by-side

added added

removed removed

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