diff -r 000000000000 -r d970ebf37754 wp/wp-admin/js/wp-fullscreen.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wp/wp-admin/js/wp-fullscreen.js Wed Nov 06 03:21:17 2013 +0000 @@ -0,0 +1,725 @@ +/** + * PubSub + * + * A lightweight publish/subscribe implementation. + * Private use only! + */ +var PubSub, fullscreen, wptitlehint; + +PubSub = function() { + this.topics = {}; +}; + +PubSub.prototype.subscribe = function( topic, callback ) { + if ( ! this.topics[ topic ] ) + this.topics[ topic ] = []; + + this.topics[ topic ].push( callback ); + return callback; +}; + +PubSub.prototype.unsubscribe = function( topic, callback ) { + var i, l, + topics = this.topics[ topic ]; + + if ( ! topics ) + return callback || []; + + // Clear matching callbacks + if ( callback ) { + for ( i = 0, l = topics.length; i < l; i++ ) { + if ( callback == topics[i] ) + topics.splice( i, 1 ); + } + return callback; + + // Clear all callbacks + } else { + this.topics[ topic ] = []; + return topics; + } +}; + +PubSub.prototype.publish = function( topic, args ) { + var i, l, broken, + topics = this.topics[ topic ]; + + if ( ! topics ) + return; + + args = args || []; + + for ( i = 0, l = topics.length; i < l; i++ ) { + broken = ( topics[i].apply( null, args ) === false || broken ); + } + return ! broken; +}; + +/** + * Distraction Free Writing + * (wp-fullscreen) + * + * Access the API globally using the fullscreen variable. + */ + +(function($){ + var api, ps, bounder, s; + + // Initialize the fullscreen/api object + fullscreen = api = {}; + + // Create the PubSub (publish/subscribe) interface. + ps = api.pubsub = new PubSub(); + timer = 0; + block = false; + + s = api.settings = { // Settings + visible : false, + mode : 'tinymce', + editor_id : 'content', + title_id : '', + timer : 0, + toolbar_shown : false + } + + /** + * Bounder + * + * Creates a function that publishes start/stop topics. + * Used to throttle events. + */ + bounder = api.bounder = function( start, stop, delay, e ) { + var y, top; + + delay = delay || 1250; + + if ( e ) { + y = e.pageY || e.clientY || e.offsetY; + top = $(document).scrollTop(); + + if ( !e.isDefaultPrevented ) // test if e ic jQuery normalized + y = 135 + y; + + if ( y - top > 120 ) + return; + } + + if ( block ) + return; + + block = true; + + setTimeout( function() { + block = false; + }, 400 ); + + if ( s.timer ) + clearTimeout( s.timer ); + else + ps.publish( start ); + + function timed() { + ps.publish( stop ); + s.timer = 0; + } + + s.timer = setTimeout( timed, delay ); + }; + + /** + * on() + * + * Turns fullscreen on. + * + * @param string mode Optional. Switch to the given mode before opening. + */ + api.on = function() { + if ( s.visible ) + return; + + // Settings can be added or changed by defining "wp_fullscreen_settings" JS object. + if ( typeof(wp_fullscreen_settings) == 'object' ) + $.extend( s, wp_fullscreen_settings ); + + s.editor_id = wpActiveEditor || 'content'; + + if ( $('input#title').length && s.editor_id == 'content' ) + s.title_id = 'title'; + else if ( $('input#' + s.editor_id + '-title').length ) // the title input field should have [editor_id]-title HTML ID to be auto detected + s.title_id = s.editor_id + '-title'; + else + $('#wp-fullscreen-title, #wp-fullscreen-title-prompt-text').hide(); + + s.mode = $('#' + s.editor_id).is(':hidden') ? 'tinymce' : 'html'; + s.qt_canvas = $('#' + s.editor_id).get(0); + + if ( ! s.element ) + api.ui.init(); + + s.is_mce_on = s.has_tinymce && typeof( tinyMCE.get(s.editor_id) ) != 'undefined'; + + api.ui.fade( 'show', 'showing', 'shown' ); + }; + + /** + * off() + * + * Turns fullscreen off. + */ + api.off = function() { + if ( ! s.visible ) + return; + + api.ui.fade( 'hide', 'hiding', 'hidden' ); + }; + + /** + * switchmode() + * + * @return string - The current mode. + * + * @param string to - The fullscreen mode to switch to. + * @event switchMode + * @eventparam string to - The new mode. + * @eventparam string from - The old mode. + */ + api.switchmode = function( to ) { + var from = s.mode; + + if ( ! to || ! s.visible || ! s.has_tinymce ) + return from; + + // Don't switch if the mode is the same. + if ( from == to ) + return from; + + ps.publish( 'switchMode', [ from, to ] ); + s.mode = to; + ps.publish( 'switchedMode', [ from, to ] ); + + return to; + }; + + /** + * General + */ + + api.save = function() { + var hidden = $('#hiddenaction'), old = hidden.val(), spinner = $('#wp-fullscreen-save .spinner'), + message = $('#wp-fullscreen-save span'); + + spinner.show(); + api.savecontent(); + + hidden.val('wp-fullscreen-save-post'); + + $.post( ajaxurl, $('form#post').serialize(), function(r){ + spinner.hide(); + message.show(); + + setTimeout( function(){ + message.fadeOut(1000); + }, 3000 ); + + if ( r.last_edited ) + $('#wp-fullscreen-save input').attr( 'title', r.last_edited ); + + }, 'json'); + + hidden.val(old); + } + + api.savecontent = function() { + var ed, content; + + if ( s.title_id ) + $('#' + s.title_id).val( $('#wp-fullscreen-title').val() ); + + if ( s.mode === 'tinymce' && (ed = tinyMCE.get('wp_mce_fullscreen')) ) { + content = ed.save(); + } else { + content = $('#wp_mce_fullscreen').val(); + } + + $('#' + s.editor_id).val( content ); + $(document).triggerHandler('wpcountwords', [ content ]); + } + + set_title_hint = function( title ) { + if ( ! title.val().length ) + title.siblings('label').css( 'visibility', '' ); + else + title.siblings('label').css( 'visibility', 'hidden' ); + } + + api.dfw_width = function(n) { + var el = $('#wp-fullscreen-wrap'), w = el.width(); + + if ( !n ) { // reset to theme width + el.width( $('#wp-fullscreen-central-toolbar').width() ); + deleteUserSetting('dfw_width'); + return; + } + + w = n + w; + + if ( w < 200 || w > 1200 ) // sanity check + return; + + el.width( w ); + setUserSetting('dfw_width', w); + } + + ps.subscribe( 'showToolbar', function() { + s.toolbars.removeClass('fade-1000').addClass('fade-300'); + api.fade.In( s.toolbars, 300, function(){ ps.publish('toolbarShown'); }, true ); + $('#wp-fullscreen-body').addClass('wp-fullscreen-focus'); + s.toolbar_shown = true; + }); + + ps.subscribe( 'hideToolbar', function() { + s.toolbars.removeClass('fade-300').addClass('fade-1000'); + api.fade.Out( s.toolbars, 1000, function(){ ps.publish('toolbarHidden'); }, true ); + $('#wp-fullscreen-body').removeClass('wp-fullscreen-focus'); + }); + + ps.subscribe( 'toolbarShown', function() { + s.toolbars.removeClass('fade-300'); + }); + + ps.subscribe( 'toolbarHidden', function() { + s.toolbars.removeClass('fade-1000'); + s.toolbar_shown = false; + }); + + ps.subscribe( 'show', function() { // This event occurs before the overlay blocks the UI. + var title; + + if ( s.title_id ) { + title = $('#wp-fullscreen-title').val( $('#' + s.title_id).val() ); + set_title_hint( title ); + } + + $('#wp-fullscreen-save input').attr( 'title', $('#last-edit').text() ); + + s.textarea_obj.value = s.qt_canvas.value; + + if ( s.has_tinymce && s.mode === 'tinymce' ) + tinyMCE.execCommand('wpFullScreenInit'); + + s.orig_y = $(window).scrollTop(); + }); + + ps.subscribe( 'showing', function() { // This event occurs while the DFW overlay blocks the UI. + $( document.body ).addClass( 'fullscreen-active' ); + api.refresh_buttons(); + + $( document ).bind( 'mousemove.fullscreen', function(e) { bounder( 'showToolbar', 'hideToolbar', 2000, e ); } ); + bounder( 'showToolbar', 'hideToolbar', 2000 ); + + api.bind_resize(); + setTimeout( api.resize_textarea, 200 ); + + // scroll to top so the user is not disoriented + scrollTo(0, 0); + + // needed it for IE7 and compat mode + $('#wpadminbar').hide(); + }); + + ps.subscribe( 'shown', function() { // This event occurs after the DFW overlay is shown + var interim_init; + + s.visible = true; + + // init the standard TinyMCE instance if missing + if ( s.has_tinymce && ! s.is_mce_on ) { + + interim_init = function(mce, ed) { + var el = ed.getElement(), old_val = el.value, settings = tinyMCEPreInit.mceInit[s.editor_id]; + + if ( settings && settings.wpautop && typeof(switchEditors) != 'undefined' ) + el.value = switchEditors.wpautop( el.value ); + + ed.onInit.add(function(ed) { + ed.hide(); + ed.getElement().value = old_val; + tinymce.onAddEditor.remove(interim_init); + }); + }; + + tinymce.onAddEditor.add(interim_init); + tinyMCE.init(tinyMCEPreInit.mceInit[s.editor_id]); + + s.is_mce_on = true; + } + + wpActiveEditor = 'wp_mce_fullscreen'; + }); + + ps.subscribe( 'hide', function() { // This event occurs before the overlay blocks DFW. + var htmled_is_hidden = $('#' + s.editor_id).is(':hidden'); + // Make sure the correct editor is displaying. + if ( s.has_tinymce && s.mode === 'tinymce' && !htmled_is_hidden ) { + switchEditors.go(s.editor_id, 'tmce'); + } else if ( s.mode === 'html' && htmled_is_hidden ) { + switchEditors.go(s.editor_id, 'html'); + } + + // Save content must be after switchEditors or content will be overwritten. See #17229. + api.savecontent(); + + $( document ).unbind( '.fullscreen' ); + $(s.textarea_obj).unbind('.grow'); + + if ( s.has_tinymce && s.mode === 'tinymce' ) + tinyMCE.execCommand('wpFullScreenSave'); + + if ( s.title_id ) + set_title_hint( $('#' + s.title_id) ); + + s.qt_canvas.value = s.textarea_obj.value; + }); + + ps.subscribe( 'hiding', function() { // This event occurs while the overlay blocks the DFW UI. + + $( document.body ).removeClass( 'fullscreen-active' ); + scrollTo(0, s.orig_y); + $('#wpadminbar').show(); + }); + + ps.subscribe( 'hidden', function() { // This event occurs after DFW is removed. + s.visible = false; + $('#wp_mce_fullscreen, #wp-fullscreen-title').removeAttr('style'); + + if ( s.has_tinymce && s.is_mce_on ) + tinyMCE.execCommand('wpFullScreenClose'); + + s.textarea_obj.value = ''; + api.oldheight = 0; + wpActiveEditor = s.editor_id; + }); + + ps.subscribe( 'switchMode', function( from, to ) { + var ed; + + if ( !s.has_tinymce || !s.is_mce_on ) + return; + + ed = tinyMCE.get('wp_mce_fullscreen'); + + if ( from === 'html' && to === 'tinymce' ) { + + if ( tinyMCE.get(s.editor_id).getParam('wpautop') && typeof(switchEditors) != 'undefined' ) + s.textarea_obj.value = switchEditors.wpautop( s.textarea_obj.value ); + + if ( 'undefined' == typeof(ed) ) + tinyMCE.execCommand('wpFullScreenInit'); + else + ed.show(); + + } else if ( from === 'tinymce' && to === 'html' ) { + if ( ed ) + ed.hide(); + } + }); + + ps.subscribe( 'switchedMode', function( from, to ) { + api.refresh_buttons(true); + + if ( to === 'html' ) + setTimeout( api.resize_textarea, 200 ); + }); + + /** + * Buttons + */ + api.b = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('Bold'); + } + + api.i = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('Italic'); + } + + api.ul = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('InsertUnorderedList'); + } + + api.ol = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('InsertOrderedList'); + } + + api.link = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('WP_Link'); + else + wpLink.open(); + } + + api.unlink = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('unlink'); + } + + api.atd = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('mceWritingImprovementTool'); + } + + api.help = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('WP_Help'); + } + + api.blockquote = function() { + if ( s.has_tinymce && 'tinymce' === s.mode ) + tinyMCE.execCommand('mceBlockQuote'); + } + + api.medialib = function() { + if ( typeof wp !== 'undefined' && wp.media && wp.media.editor ) + wp.media.editor.open(s.editor_id); + } + + api.refresh_buttons = function( fade ) { + fade = fade || false; + + if ( s.mode === 'html' ) { + $('#wp-fullscreen-mode-bar').removeClass('wp-tmce-mode').addClass('wp-html-mode'); + + if ( fade ) + $('#wp-fullscreen-button-bar').fadeOut( 150, function(){ + $(this).addClass('wp-html-mode').fadeIn( 150 ); + }); + else + $('#wp-fullscreen-button-bar').addClass('wp-html-mode'); + + } else if ( s.mode === 'tinymce' ) { + $('#wp-fullscreen-mode-bar').removeClass('wp-html-mode').addClass('wp-tmce-mode'); + + if ( fade ) + $('#wp-fullscreen-button-bar').fadeOut( 150, function(){ + $(this).removeClass('wp-html-mode').fadeIn( 150 ); + }); + else + $('#wp-fullscreen-button-bar').removeClass('wp-html-mode'); + } + } + + /** + * UI Elements + * + * Used for transitioning between states. + */ + api.ui = { + init: function() { + var topbar = $('#fullscreen-topbar'), txtarea = $('#wp_mce_fullscreen'), last = 0; + + s.toolbars = topbar.add( $('#wp-fullscreen-status') ); + s.element = $('#fullscreen-fader'); + s.textarea_obj = txtarea[0]; + s.has_tinymce = typeof(tinymce) != 'undefined'; + + if ( !s.has_tinymce ) + $('#wp-fullscreen-mode-bar').hide(); + + if ( wptitlehint && $('#wp-fullscreen-title').length ) + wptitlehint('wp-fullscreen-title'); + + $(document).keyup(function(e){ + var c = e.keyCode || e.charCode, a, data; + + if ( !fullscreen.settings.visible ) + return true; + + if ( navigator.platform && navigator.platform.indexOf('Mac') != -1 ) + a = e.ctrlKey; // Ctrl key for Mac + else + a = e.altKey; // Alt key for Win & Linux + + if ( 27 == c ) { // Esc + data = { + event: e, + what: 'dfw', + cb: fullscreen.off, + condition: function(){ + if ( $('#TB_window').is(':visible') || $('.wp-dialog').is(':visible') ) + return false; + return true; + } + }; + + if ( ! jQuery(document).triggerHandler( 'wp_CloseOnEscape', [data] ) ) + fullscreen.off(); + } + + if ( a && (61 == c || 107 == c || 187 == c) ) // + + api.dfw_width(25); + + if ( a && (45 == c || 109 == c || 189 == c) ) // - + api.dfw_width(-25); + + if ( a && 48 == c ) // 0 + api.dfw_width(0); + + return false; + }); + + // word count in Text mode + if ( typeof(wpWordCount) != 'undefined' ) { + + txtarea.keyup( function(e) { + var k = e.keyCode || e.charCode; + + if ( k == last ) + return true; + + if ( 13 == k || 8 == last || 46 == last ) + $(document).triggerHandler('wpcountwords', [ txtarea.val() ]); + + last = k; + return true; + }); + } + + topbar.mouseenter(function(e){ + s.toolbars.addClass('fullscreen-make-sticky'); + $( document ).unbind( '.fullscreen' ); + clearTimeout( s.timer ); + s.timer = 0; + }).mouseleave(function(e){ + s.toolbars.removeClass('fullscreen-make-sticky'); + + if ( s.visible ) + $( document ).bind( 'mousemove.fullscreen', function(e) { bounder( 'showToolbar', 'hideToolbar', 2000, e ); } ); + }); + }, + + fade: function( before, during, after ) { + if ( ! s.element ) + api.ui.init(); + + // If any callback bound to before returns false, bail. + if ( before && ! ps.publish( before ) ) + return; + + api.fade.In( s.element, 600, function() { + if ( during ) + ps.publish( during ); + + api.fade.Out( s.element, 600, function() { + if ( after ) + ps.publish( after ); + }) + }); + } + }; + + api.fade = { + transitionend: 'transitionend webkitTransitionEnd oTransitionEnd', + + // Sensitivity to allow browsers to render the blank element before animating. + sensitivity: 100, + + In: function( element, speed, callback, stop ) { + + callback = callback || $.noop; + speed = speed || 400; + stop = stop || false; + + if ( api.fade.transitions ) { + if ( element.is(':visible') ) { + element.addClass( 'fade-trigger' ); + return element; + } + + element.show(); + element.first().one( this.transitionend, function() { + callback(); + }); + setTimeout( function() { element.addClass( 'fade-trigger' ); }, this.sensitivity ); + } else { + if ( stop ) + element.stop(); + + element.css( 'opacity', 1 ); + element.first().fadeIn( speed, callback ); + + if ( element.length > 1 ) + element.not(':first').fadeIn( speed ); + } + + return element; + }, + + Out: function( element, speed, callback, stop ) { + + callback = callback || $.noop; + speed = speed || 400; + stop = stop || false; + + if ( ! element.is(':visible') ) + return element; + + if ( api.fade.transitions ) { + element.first().one( api.fade.transitionend, function() { + if ( element.hasClass('fade-trigger') ) + return; + + element.hide(); + callback(); + }); + setTimeout( function() { element.removeClass( 'fade-trigger' ); }, this.sensitivity ); + } else { + if ( stop ) + element.stop(); + + element.first().fadeOut( speed, callback ); + + if ( element.length > 1 ) + element.not(':first').fadeOut( speed ); + } + + return element; + }, + + transitions: (function() { // Check if the browser supports CSS 3.0 transitions + var s = document.documentElement.style; + + return ( typeof ( s.WebkitTransition ) == 'string' || + typeof ( s.MozTransition ) == 'string' || + typeof ( s.OTransition ) == 'string' || + typeof ( s.transition ) == 'string' ); + })() + }; + + /** + * Resize API + * + * Automatically updates textarea height. + */ + + api.bind_resize = function() { + $(s.textarea_obj).bind('keypress.grow click.grow paste.grow', function(){ + setTimeout( api.resize_textarea, 200 ); + }); + } + + api.oldheight = 0; + api.resize_textarea = function() { + var txt = s.textarea_obj, newheight; + + newheight = txt.scrollHeight > 300 ? txt.scrollHeight : 300; + + if ( newheight != api.oldheight ) { + txt.style.height = newheight + 'px'; + api.oldheight = newheight; + } + }; + +})(jQuery);