wp/wp-admin/js/wp-fullscreen.js
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
--- /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);