]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-admin/js/wp-fullscreen.js
WordPress 3.5.1-scripts
[autoinstalls/wordpress.git] / wp-admin / js / wp-fullscreen.js
1 /**
2  * PubSub
3  *
4  * A lightweight publish/subscribe implementation.
5  * Private use only!
6  */
7 var PubSub, fullscreen, wptitlehint;
8
9 PubSub = function() {
10         this.topics = {};
11 };
12
13 PubSub.prototype.subscribe = function( topic, callback ) {
14         if ( ! this.topics[ topic ] )
15                 this.topics[ topic ] = [];
16
17         this.topics[ topic ].push( callback );
18         return callback;
19 };
20
21 PubSub.prototype.unsubscribe = function( topic, callback ) {
22         var i, l,
23                 topics = this.topics[ topic ];
24
25         if ( ! topics )
26                 return callback || [];
27
28         // Clear matching callbacks
29         if ( callback ) {
30                 for ( i = 0, l = topics.length; i < l; i++ ) {
31                         if ( callback == topics[i] )
32                                 topics.splice( i, 1 );
33                 }
34                 return callback;
35
36         // Clear all callbacks
37         } else {
38                 this.topics[ topic ] = [];
39                 return topics;
40         }
41 };
42
43 PubSub.prototype.publish = function( topic, args ) {
44         var i, l, broken,
45                 topics = this.topics[ topic ];
46
47         if ( ! topics )
48                 return;
49
50         args = args || [];
51
52         for ( i = 0, l = topics.length; i < l; i++ ) {
53                 broken = ( topics[i].apply( null, args ) === false || broken );
54         }
55         return ! broken;
56 };
57
58 /**
59  * Distraction Free Writing
60  * (wp-fullscreen)
61  *
62  * Access the API globally using the fullscreen variable.
63  */
64
65 (function($){
66         var api, ps, bounder, s;
67
68         // Initialize the fullscreen/api object
69         fullscreen = api = {};
70
71         // Create the PubSub (publish/subscribe) interface.
72         ps = api.pubsub = new PubSub();
73         timer = 0;
74         block = false;
75
76         s = api.settings = { // Settings
77                 visible : false,
78                 mode : 'tinymce',
79                 editor_id : 'content',
80                 title_id : '',
81                 timer : 0,
82                 toolbar_shown : false
83         }
84
85         /**
86          * Bounder
87          *
88          * Creates a function that publishes start/stop topics.
89          * Used to throttle events.
90          */
91         bounder = api.bounder = function( start, stop, delay, e ) {
92                 var y, top;
93
94                 delay = delay || 1250;
95
96                 if ( e ) {
97                         y = e.pageY || e.clientY || e.offsetY;
98                         top = $(document).scrollTop();
99
100                         if ( !e.isDefaultPrevented ) // test if e ic jQuery normalized
101                                 y = 135 + y;
102
103                         if ( y - top > 120 )
104                                 return;
105                 }
106
107                 if ( block )
108                         return;
109
110                 block = true;
111
112                 setTimeout( function() {
113                         block = false;
114                 }, 400 );
115
116                 if ( s.timer )
117                         clearTimeout( s.timer );
118                 else
119                         ps.publish( start );
120
121                 function timed() {
122                         ps.publish( stop );
123                         s.timer = 0;
124                 }
125
126                 s.timer = setTimeout( timed, delay );
127         };
128
129         /**
130          * on()
131          *
132          * Turns fullscreen on.
133          *
134          * @param string mode Optional. Switch to the given mode before opening.
135          */
136         api.on = function() {
137                 if ( s.visible )
138                         return;
139
140                 // Settings can be added or changed by defining "wp_fullscreen_settings" JS object.
141                 if ( typeof(wp_fullscreen_settings) == 'object' )
142                         $.extend( s, wp_fullscreen_settings );
143
144                 s.editor_id = wpActiveEditor || 'content';
145
146                 if ( $('input#title').length && s.editor_id == 'content' )
147                         s.title_id = 'title';
148                 else if ( $('input#' + s.editor_id + '-title').length ) // the title input field should have [editor_id]-title HTML ID to be auto detected
149                         s.title_id = s.editor_id + '-title';
150                 else
151                         $('#wp-fullscreen-title, #wp-fullscreen-title-prompt-text').hide();
152
153                 s.mode = $('#' + s.editor_id).is(':hidden') ? 'tinymce' : 'html';
154                 s.qt_canvas = $('#' + s.editor_id).get(0);
155
156                 if ( ! s.element )
157                         api.ui.init();
158
159                 s.is_mce_on = s.has_tinymce && typeof( tinyMCE.get(s.editor_id) ) != 'undefined';
160
161                 api.ui.fade( 'show', 'showing', 'shown' );
162         };
163
164         /**
165          * off()
166          *
167          * Turns fullscreen off.
168          */
169         api.off = function() {
170                 if ( ! s.visible )
171                         return;
172
173                 api.ui.fade( 'hide', 'hiding', 'hidden' );
174         };
175
176         /**
177          * switchmode()
178          *
179          * @return string - The current mode.
180          *
181          * @param string to - The fullscreen mode to switch to.
182          * @event switchMode
183          * @eventparam string to   - The new mode.
184          * @eventparam string from - The old mode.
185          */
186         api.switchmode = function( to ) {
187                 var from = s.mode;
188
189                 if ( ! to || ! s.visible || ! s.has_tinymce )
190                         return from;
191
192                 // Don't switch if the mode is the same.
193                 if ( from == to )
194                         return from;
195
196                 ps.publish( 'switchMode', [ from, to ] );
197                 s.mode = to;
198                 ps.publish( 'switchedMode', [ from, to ] );
199
200                 return to;
201         };
202
203         /**
204          * General
205          */
206
207         api.save = function() {
208                 var hidden = $('#hiddenaction'), old = hidden.val(), spinner = $('#wp-fullscreen-save .spinner'),
209                         message = $('#wp-fullscreen-save span');
210
211                 spinner.show();
212                 api.savecontent();
213
214                 hidden.val('wp-fullscreen-save-post');
215
216                 $.post( ajaxurl, $('form#post').serialize(), function(r){
217                         spinner.hide();
218                         message.show();
219
220                         setTimeout( function(){
221                                 message.fadeOut(1000);
222                         }, 3000 );
223
224                         if ( r.last_edited )
225                                 $('#wp-fullscreen-save input').attr( 'title',  r.last_edited );
226
227                 }, 'json');
228
229                 hidden.val(old);
230         }
231
232         api.savecontent = function() {
233                 var ed, content;
234
235                 if ( s.title_id )
236                         $('#' + s.title_id).val( $('#wp-fullscreen-title').val() );
237
238                 if ( s.mode === 'tinymce' && (ed = tinyMCE.get('wp_mce_fullscreen')) ) {
239                         content = ed.save();
240                 } else {
241                         content = $('#wp_mce_fullscreen').val();
242                 }
243
244                 $('#' + s.editor_id).val( content );
245                 $(document).triggerHandler('wpcountwords', [ content ]);
246         }
247
248         set_title_hint = function( title ) {
249                 if ( ! title.val().length )
250                         title.siblings('label').css( 'visibility', '' );
251                 else
252                         title.siblings('label').css( 'visibility', 'hidden' );
253         }
254
255         api.dfw_width = function(n) {
256                 var el = $('#wp-fullscreen-wrap'), w = el.width();
257
258                 if ( !n ) { // reset to theme width
259                         el.width( $('#wp-fullscreen-central-toolbar').width() );
260                         deleteUserSetting('dfw_width');
261                         return;
262                 }
263
264                 w = n + w;
265
266                 if ( w < 200 || w > 1200 ) // sanity check
267                         return;
268
269                 el.width( w );
270                 setUserSetting('dfw_width', w);
271         }
272
273         ps.subscribe( 'showToolbar', function() {
274                 s.toolbars.removeClass('fade-1000').addClass('fade-300');
275                 api.fade.In( s.toolbars, 300, function(){ ps.publish('toolbarShown'); }, true );
276                 $('#wp-fullscreen-body').addClass('wp-fullscreen-focus');
277                 s.toolbar_shown = true;
278         });
279
280         ps.subscribe( 'hideToolbar', function() {
281                 s.toolbars.removeClass('fade-300').addClass('fade-1000');
282                 api.fade.Out( s.toolbars, 1000, function(){ ps.publish('toolbarHidden'); }, true );
283                 $('#wp-fullscreen-body').removeClass('wp-fullscreen-focus');
284         });
285
286         ps.subscribe( 'toolbarShown', function() {
287                 s.toolbars.removeClass('fade-300');
288         });
289
290         ps.subscribe( 'toolbarHidden', function() {
291                 s.toolbars.removeClass('fade-1000');
292                 s.toolbar_shown = false;
293         });
294
295         ps.subscribe( 'show', function() { // This event occurs before the overlay blocks the UI.
296                 var title;
297
298                 if ( s.title_id ) {
299                         title = $('#wp-fullscreen-title').val( $('#' + s.title_id).val() );
300                         set_title_hint( title );
301                 }
302
303                 $('#wp-fullscreen-save input').attr( 'title',  $('#last-edit').text() );
304
305                 s.textarea_obj.value = s.qt_canvas.value;
306
307                 if ( s.has_tinymce && s.mode === 'tinymce' )
308                         tinyMCE.execCommand('wpFullScreenInit');
309
310                 s.orig_y = $(window).scrollTop();
311         });
312
313         ps.subscribe( 'showing', function() { // This event occurs while the DFW overlay blocks the UI.
314                 $( document.body ).addClass( 'fullscreen-active' );
315                 api.refresh_buttons();
316
317                 $( document ).bind( 'mousemove.fullscreen', function(e) { bounder( 'showToolbar', 'hideToolbar', 2000, e ); } );
318                 bounder( 'showToolbar', 'hideToolbar', 2000 );
319
320                 api.bind_resize();
321                 setTimeout( api.resize_textarea, 200 );
322
323                 // scroll to top so the user is not disoriented
324                 scrollTo(0, 0);
325
326                 // needed it for IE7 and compat mode
327                 $('#wpadminbar').hide();
328         });
329
330         ps.subscribe( 'shown', function() { // This event occurs after the DFW overlay is shown
331                 var interim_init;
332
333                 s.visible = true;
334
335                 // init the standard TinyMCE instance if missing
336                 if ( s.has_tinymce && ! s.is_mce_on ) {
337
338                         interim_init = function(mce, ed) {
339                                 var el = ed.getElement(), old_val = el.value, settings = tinyMCEPreInit.mceInit[s.editor_id];
340
341                                 if ( settings && settings.wpautop && typeof(switchEditors) != 'undefined' )
342                                         el.value = switchEditors.wpautop( el.value );
343
344                                 ed.onInit.add(function(ed) {
345                                         ed.hide();
346                                         ed.getElement().value = old_val;
347                                         tinymce.onAddEditor.remove(interim_init);
348                                 });
349                         };
350
351                         tinymce.onAddEditor.add(interim_init);
352                         tinyMCE.init(tinyMCEPreInit.mceInit[s.editor_id]);
353
354                         s.is_mce_on = true;
355                 }
356
357                 wpActiveEditor = 'wp_mce_fullscreen';
358         });
359
360         ps.subscribe( 'hide', function() { // This event occurs before the overlay blocks DFW.
361                 var htmled_is_hidden = $('#' + s.editor_id).is(':hidden');
362                 // Make sure the correct editor is displaying.
363                 if ( s.has_tinymce && s.mode === 'tinymce' && !htmled_is_hidden ) {
364                         switchEditors.go(s.editor_id, 'tmce');
365                 } else if ( s.mode === 'html' && htmled_is_hidden ) {
366                         switchEditors.go(s.editor_id, 'html');
367                 }
368
369                 // Save content must be after switchEditors or content will be overwritten. See #17229.
370                 api.savecontent();
371
372                 $( document ).unbind( '.fullscreen' );
373                 $(s.textarea_obj).unbind('.grow');
374
375                 if ( s.has_tinymce && s.mode === 'tinymce' )
376                         tinyMCE.execCommand('wpFullScreenSave');
377
378                 if ( s.title_id )
379                         set_title_hint( $('#' + s.title_id) );
380
381                 s.qt_canvas.value = s.textarea_obj.value;
382         });
383
384         ps.subscribe( 'hiding', function() { // This event occurs while the overlay blocks the DFW UI.
385
386                 $( document.body ).removeClass( 'fullscreen-active' );
387                 scrollTo(0, s.orig_y);
388                 $('#wpadminbar').show();
389         });
390
391         ps.subscribe( 'hidden', function() { // This event occurs after DFW is removed.
392                 s.visible = false;
393                 $('#wp_mce_fullscreen, #wp-fullscreen-title').removeAttr('style');
394
395                 if ( s.has_tinymce && s.is_mce_on )
396                         tinyMCE.execCommand('wpFullScreenClose');
397
398                 s.textarea_obj.value = '';
399                 api.oldheight = 0;
400                 wpActiveEditor = s.editor_id;
401         });
402
403         ps.subscribe( 'switchMode', function( from, to ) {
404                 var ed;
405
406                 if ( !s.has_tinymce || !s.is_mce_on )
407                         return;
408
409                 ed = tinyMCE.get('wp_mce_fullscreen');
410
411                 if ( from === 'html' && to === 'tinymce' ) {
412
413                         if ( tinyMCE.get(s.editor_id).getParam('wpautop') && typeof(switchEditors) != 'undefined' )
414                                 s.textarea_obj.value = switchEditors.wpautop( s.textarea_obj.value );
415
416                         if ( 'undefined' == typeof(ed) )
417                                 tinyMCE.execCommand('wpFullScreenInit');
418                         else
419                                 ed.show();
420
421                 } else if ( from === 'tinymce' && to === 'html' ) {
422                         if ( ed )
423                                 ed.hide();
424                 }
425         });
426
427         ps.subscribe( 'switchedMode', function( from, to ) {
428                 api.refresh_buttons(true);
429
430                 if ( to === 'html' )
431                         setTimeout( api.resize_textarea, 200 );
432         });
433
434         /**
435          * Buttons
436          */
437         api.b = function() {
438                 if ( s.has_tinymce && 'tinymce' === s.mode )
439                         tinyMCE.execCommand('Bold');
440         }
441
442         api.i = function() {
443                 if ( s.has_tinymce && 'tinymce' === s.mode )
444                         tinyMCE.execCommand('Italic');
445         }
446
447         api.ul = function() {
448                 if ( s.has_tinymce && 'tinymce' === s.mode )
449                         tinyMCE.execCommand('InsertUnorderedList');
450         }
451
452         api.ol = function() {
453                 if ( s.has_tinymce && 'tinymce' === s.mode )
454                         tinyMCE.execCommand('InsertOrderedList');
455         }
456
457         api.link = function() {
458                 if ( s.has_tinymce && 'tinymce' === s.mode )
459                         tinyMCE.execCommand('WP_Link');
460                 else
461                         wpLink.open();
462         }
463
464         api.unlink = function() {
465                 if ( s.has_tinymce && 'tinymce' === s.mode )
466                         tinyMCE.execCommand('unlink');
467         }
468
469         api.atd = function() {
470                 if ( s.has_tinymce && 'tinymce' === s.mode )
471                         tinyMCE.execCommand('mceWritingImprovementTool');
472         }
473
474         api.help = function() {
475                 if ( s.has_tinymce && 'tinymce' === s.mode )
476                         tinyMCE.execCommand('WP_Help');
477         }
478
479         api.blockquote = function() {
480                 if ( s.has_tinymce && 'tinymce' === s.mode )
481                         tinyMCE.execCommand('mceBlockQuote');
482         }
483
484         api.medialib = function() {
485                 if ( typeof wp !== 'undefined' && wp.media && wp.media.editor )
486                         wp.media.editor.open(s.editor_id);
487         }
488
489         api.refresh_buttons = function( fade ) {
490                 fade = fade || false;
491
492                 if ( s.mode === 'html' ) {
493                         $('#wp-fullscreen-mode-bar').removeClass('wp-tmce-mode').addClass('wp-html-mode');
494
495                         if ( fade )
496                                 $('#wp-fullscreen-button-bar').fadeOut( 150, function(){
497                                         $(this).addClass('wp-html-mode').fadeIn( 150 );
498                                 });
499                         else
500                                 $('#wp-fullscreen-button-bar').addClass('wp-html-mode');
501
502                 } else if ( s.mode === 'tinymce' ) {
503                         $('#wp-fullscreen-mode-bar').removeClass('wp-html-mode').addClass('wp-tmce-mode');
504
505                         if ( fade )
506                                 $('#wp-fullscreen-button-bar').fadeOut( 150, function(){
507                                         $(this).removeClass('wp-html-mode').fadeIn( 150 );
508                                 });
509                         else
510                                 $('#wp-fullscreen-button-bar').removeClass('wp-html-mode');
511                 }
512         }
513
514         /**
515          * UI Elements
516          *
517          * Used for transitioning between states.
518          */
519         api.ui = {
520                 init: function() {
521                         var topbar = $('#fullscreen-topbar'), txtarea = $('#wp_mce_fullscreen'), last = 0;
522
523                         s.toolbars = topbar.add( $('#wp-fullscreen-status') );
524                         s.element = $('#fullscreen-fader');
525                         s.textarea_obj = txtarea[0];
526                         s.has_tinymce = typeof(tinymce) != 'undefined';
527
528                         if ( !s.has_tinymce )
529                                 $('#wp-fullscreen-mode-bar').hide();
530
531                         if ( wptitlehint && $('#wp-fullscreen-title').length )
532                                 wptitlehint('wp-fullscreen-title');
533
534                         $(document).keyup(function(e){
535                                 var c = e.keyCode || e.charCode, a, data;
536
537                                 if ( !fullscreen.settings.visible )
538                                         return true;
539
540                                 if ( navigator.platform && navigator.platform.indexOf('Mac') != -1 )
541                                         a = e.ctrlKey; // Ctrl key for Mac
542                                 else
543                                         a = e.altKey; // Alt key for Win & Linux
544
545                                 if ( 27 == c ) { // Esc
546                                         data = {
547                                                 event: e,
548                                                 what: 'dfw',
549                                                 cb: fullscreen.off,
550                                                 condition: function(){
551                                                         if ( $('#TB_window').is(':visible') || $('.wp-dialog').is(':visible') )
552                                                                 return false;
553                                                         return true;
554                                                 }
555                                         };
556
557                                         if ( ! jQuery(document).triggerHandler( 'wp_CloseOnEscape', [data] ) )
558                                                 fullscreen.off();
559                                 }
560
561                                 if ( a && (61 == c || 107 == c || 187 == c) ) // +
562                                         api.dfw_width(25);
563
564                                 if ( a && (45 == c || 109 == c || 189 == c) ) // -
565                                         api.dfw_width(-25);
566
567                                 if ( a && 48 == c ) // 0
568                                         api.dfw_width(0);
569
570                                 return false;
571                         });
572
573                         // word count in Text mode
574                         if ( typeof(wpWordCount) != 'undefined' ) {
575
576                                 txtarea.keyup( function(e) {
577                                         var k = e.keyCode || e.charCode;
578
579                                         if ( k == last )
580                                                 return true;
581
582                                         if ( 13 == k || 8 == last || 46 == last )
583                                                 $(document).triggerHandler('wpcountwords', [ txtarea.val() ]);
584
585                                         last = k;
586                                         return true;
587                                 });
588                         }
589
590                         topbar.mouseenter(function(e){
591                                 s.toolbars.addClass('fullscreen-make-sticky');
592                                 $( document ).unbind( '.fullscreen' );
593                                 clearTimeout( s.timer );
594                                 s.timer = 0;
595                         }).mouseleave(function(e){
596                                 s.toolbars.removeClass('fullscreen-make-sticky');
597
598                                 if ( s.visible )
599                                         $( document ).bind( 'mousemove.fullscreen', function(e) { bounder( 'showToolbar', 'hideToolbar', 2000, e ); } );
600                         });
601                 },
602
603                 fade: function( before, during, after ) {
604                         if ( ! s.element )
605                                 api.ui.init();
606
607                         // If any callback bound to before returns false, bail.
608                         if ( before && ! ps.publish( before ) )
609                                 return;
610
611                         api.fade.In( s.element, 600, function() {
612                                 if ( during )
613                                         ps.publish( during );
614
615                                 api.fade.Out( s.element, 600, function() {
616                                         if ( after )
617                                                 ps.publish( after );
618                                 })
619                         });
620                 }
621         };
622
623         api.fade = {
624                 transitionend: 'transitionend webkitTransitionEnd oTransitionEnd',
625
626                 // Sensitivity to allow browsers to render the blank element before animating.
627                 sensitivity: 100,
628
629                 In: function( element, speed, callback, stop ) {
630
631                         callback = callback || $.noop;
632                         speed = speed || 400;
633                         stop = stop || false;
634
635                         if ( api.fade.transitions ) {
636                                 if ( element.is(':visible') ) {
637                                         element.addClass( 'fade-trigger' );
638                                         return element;
639                                 }
640
641                                 element.show();
642                                 element.first().one( this.transitionend, function() {
643                                         callback();
644                                 });
645                                 setTimeout( function() { element.addClass( 'fade-trigger' ); }, this.sensitivity );
646                         } else {
647                                 if ( stop )
648                                         element.stop();
649
650                                 element.css( 'opacity', 1 );
651                                 element.first().fadeIn( speed, callback );
652
653                                 if ( element.length > 1 )
654                                         element.not(':first').fadeIn( speed );
655                         }
656
657                         return element;
658                 },
659
660                 Out: function( element, speed, callback, stop ) {
661
662                         callback = callback || $.noop;
663                         speed = speed || 400;
664                         stop = stop || false;
665
666                         if ( ! element.is(':visible') )
667                                 return element;
668
669                         if ( api.fade.transitions ) {
670                                 element.first().one( api.fade.transitionend, function() {
671                                         if ( element.hasClass('fade-trigger') )
672                                                 return;
673
674                                         element.hide();
675                                         callback();
676                                 });
677                                 setTimeout( function() { element.removeClass( 'fade-trigger' ); }, this.sensitivity );
678                         } else {
679                                 if ( stop )
680                                         element.stop();
681
682                                 element.first().fadeOut( speed, callback );
683
684                                 if ( element.length > 1 )
685                                         element.not(':first').fadeOut( speed );
686                         }
687
688                         return element;
689                 },
690
691                 transitions: (function() { // Check if the browser supports CSS 3.0 transitions
692                         var s = document.documentElement.style;
693
694                         return ( typeof ( s.WebkitTransition ) == 'string' ||
695                                 typeof ( s.MozTransition ) == 'string' ||
696                                 typeof ( s.OTransition ) == 'string' ||
697                                 typeof ( s.transition ) == 'string' );
698                 })()
699         };
700
701         /**
702          * Resize API
703          *
704          * Automatically updates textarea height.
705          */
706
707         api.bind_resize = function() {
708                 $(s.textarea_obj).bind('keypress.grow click.grow paste.grow', function(){
709                         setTimeout( api.resize_textarea, 200 );
710                 });
711         }
712
713         api.oldheight = 0;
714         api.resize_textarea = function() {
715                 var txt = s.textarea_obj, newheight;
716
717                 newheight = txt.scrollHeight > 300 ? txt.scrollHeight : 300;
718
719                 if ( newheight != api.oldheight ) {
720                         txt.style.height = newheight + 'px';
721                         api.oldheight = newheight;
722                 }
723         };
724
725 })(jQuery);