]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/js/tinymce/plugins/wordpress/plugin.js
WordPress 4.0
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / plugins / wordpress / plugin.js
1 /* global tinymce, getUserSetting, setUserSetting */
2
3 // Set the minimum value for the modals z-index higher than #wpadminbar (100000)
4 tinymce.ui.FloatPanel.zIndex = 100100;
5
6 tinymce.PluginManager.add( 'wordpress', function( editor ) {
7         var DOM = tinymce.DOM, wpAdvButton, modKey, style,
8                 last = 0;
9
10         function toggleToolbars( state ) {
11                 var iframe, initial, toolbars,
12                         pixels = 0;
13
14                 initial = ( state === 'hide' );
15
16                 if ( editor.theme.panel ) {
17                         toolbars = editor.theme.panel.find('.toolbar:not(.menubar)');
18                 }
19
20                 if ( ! toolbars || toolbars.length < 2 || ( state === 'hide' && ! toolbars[1].visible() ) ) {
21                         return;
22                 }
23
24                 if ( ! state && toolbars[1].visible() ) {
25                         state = 'hide';
26                 }
27
28                 tinymce.each( toolbars, function( toolbar, i ) {
29                         if ( i > 0 ) {
30                                 if ( state === 'hide' ) {
31                                         toolbar.hide();
32                                         pixels += 30;
33                                 } else {
34                                         toolbar.show();
35                                         pixels -= 30;
36                                 }
37                         }
38                 });
39
40                 if ( pixels && ! initial ) {
41                         // Resize iframe, not needed in iOS
42                         if ( ! tinymce.Env.iOS ) {
43                                 iframe = editor.getContentAreaContainer().firstChild;
44                                 DOM.setStyle( iframe, 'height', iframe.clientHeight + pixels );
45                         }
46
47                         if ( state === 'hide' ) {
48                                 setUserSetting('hidetb', '0');
49                                 wpAdvButton && wpAdvButton.active( false );
50                         } else {
51                                 setUserSetting('hidetb', '1');
52                                 wpAdvButton && wpAdvButton.active( true );
53                         }
54                 }
55
56                 editor.fire( 'wp-toolbar-toggle' );
57         }
58
59         // Add the kitchen sink button :)
60         editor.addButton( 'wp_adv', {
61                 tooltip: 'Toolbar Toggle',
62                 cmd: 'WP_Adv',
63                 onPostRender: function() {
64                         wpAdvButton = this;
65                         wpAdvButton.active( getUserSetting( 'hidetb' ) === '1' ? true : false );
66                 }
67         });
68
69         // Hide the toolbars after loading
70         editor.on( 'PostRender', function() {
71                 if ( editor.getParam( 'wordpress_adv_hidden', true ) && getUserSetting( 'hidetb', '0' ) === '0' ) {
72                         toggleToolbars( 'hide' );
73                 }
74         });
75
76         editor.addCommand( 'WP_Adv', function() {
77                 toggleToolbars();
78         });
79
80         editor.on( 'focus', function() {
81         window.wpActiveEditor = editor.id;
82     });
83
84         // Replace Read More/Next Page tags with images
85         editor.on( 'BeforeSetContent', function( e ) {
86                 var title;
87
88                 if ( e.content ) {
89                         if ( e.content.indexOf( '<!--more' ) !== -1 ) {
90                                 title = editor.editorManager.i18n.translate( 'Read more...' );
91
92                                 e.content = e.content.replace( /<!--more(.*?)-->/g, function( match, moretext ) {
93                                         return '<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="more" data-wp-more-text="' + moretext + '" ' +
94                                                 'class="wp-more-tag mce-wp-more" title="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />';
95                                 });
96                         }
97
98                         if ( e.content.indexOf( '<!--nextpage-->' ) !== -1 ) {
99                                 title = editor.editorManager.i18n.translate( 'Page break' );
100
101                                 e.content = e.content.replace( /<!--nextpage-->/g,
102                                         '<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="nextpage" class="wp-more-tag mce-wp-nextpage" ' +
103                                                 'title="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />' );
104                         }
105                 }
106         });
107
108         // Replace images with tags
109         editor.on( 'PostProcess', function( e ) {
110                 if ( e.get ) {
111                         e.content = e.content.replace(/<img[^>]+>/g, function( image ) {
112                                 var match, moretext = '';
113
114                                 if ( image.indexOf( 'data-wp-more="more"' ) !== -1 ) {
115                                         if ( match = image.match( /data-wp-more-text="([^"]+)"/ ) ) {
116                                                 moretext = match[1];
117                                         }
118
119                                         image = '<!--more' + moretext + '-->';
120                                 } else if ( image.indexOf( 'data-wp-more="nextpage"' ) !== -1 ) {
121                                         image = '<!--nextpage-->';
122                                 }
123
124                                 return image;
125                         });
126                 }
127         });
128
129         // Display the tag name instead of img in element path
130         editor.on( 'ResolveName', function( event ) {
131                 var attr;
132
133                 if ( event.target.nodeName === 'IMG' && ( attr = editor.dom.getAttrib( event.target, 'data-wp-more' ) ) ) {
134                         event.name = attr;
135                 }
136         });
137
138         // Register commands
139         editor.addCommand( 'WP_More', function( tag ) {
140                 var parent, html, title,
141                         classname = 'wp-more-tag',
142                         dom = editor.dom,
143                         node = editor.selection.getNode();
144
145                 tag = tag || 'more';
146                 classname += ' mce-wp-' + tag;
147                 title = tag === 'more' ? 'Read more...' : 'Next page';
148                 title = editor.editorManager.i18n.translate( title );
149                 html = '<img src="' + tinymce.Env.transparentSrc + '" title="' + title + '" class="' + classname + '" ' +
150                         'data-wp-more="' + tag + '" data-mce-resize="false" data-mce-placeholder="1" />';
151
152                 // Most common case
153                 if ( node.nodeName === 'BODY' || ( node.nodeName === 'P' && node.parentNode.nodeName === 'BODY' ) ) {
154                         editor.insertContent( html );
155                         return;
156                 }
157
158                 // Get the top level parent node
159                 parent = dom.getParent( node, function( found ) {
160                         if ( found.parentNode && found.parentNode.nodeName === 'BODY' ) {
161                                 return true;
162                         }
163
164                         return false;
165                 }, editor.getBody() );
166
167                 if ( parent ) {
168                         if ( parent.nodeName === 'P' ) {
169                                 parent.appendChild( dom.create( 'p', null, html ).firstChild );
170                         } else {
171                                 dom.insertAfter( dom.create( 'p', null, html ), parent );
172                         }
173
174                         editor.nodeChanged();
175                 }
176         });
177
178         editor.addCommand( 'WP_Code', function() {
179                 editor.formatter.toggle('code');
180         });
181
182         editor.addCommand( 'WP_Page', function() {
183                 editor.execCommand( 'WP_More', 'nextpage' );
184         });
185
186         editor.addCommand( 'WP_Help', function() {
187                 editor.windowManager.open({
188                         url: tinymce.baseURL + '/wp-mce-help.php',
189                         title: 'Keyboard Shortcuts',
190                         width: 450,
191                         height: 420,
192                         inline: 1,
193                         classes: 'wp-help'
194                 });
195         });
196
197         editor.addCommand( 'WP_Medialib', function() {
198                 if ( typeof wp !== 'undefined' && wp.media && wp.media.editor ) {
199                         wp.media.editor.open( editor.id );
200                 }
201         });
202
203         // Register buttons
204         editor.addButton( 'wp_more', {
205                 tooltip: 'Insert Read More tag',
206                 onclick: function() {
207                         editor.execCommand( 'WP_More', 'more' );
208                 }
209         });
210
211         editor.addButton( 'wp_page', {
212                 tooltip: 'Page break',
213                 onclick: function() {
214                         editor.execCommand( 'WP_More', 'nextpage' );
215                 }
216         });
217
218         editor.addButton( 'wp_help', {
219                 tooltip: 'Keyboard Shortcuts',
220                 cmd: 'WP_Help'
221         });
222
223         editor.addButton( 'wp_code', {
224                 tooltip: 'Code',
225                 cmd: 'WP_Code',
226                 stateSelector: 'code'
227         });
228
229         // Menubar
230         // Insert->Add Media
231         if ( typeof wp !== 'undefined' && wp.media && wp.media.editor ) {
232                 editor.addMenuItem( 'add_media', {
233                         text: 'Add Media',
234                         icon: 'wp-media-library',
235                         context: 'insert',
236                         cmd: 'WP_Medialib'
237                 });
238         }
239
240         // Insert "Read More..."
241         editor.addMenuItem( 'wp_more', {
242                 text: 'Insert Read More tag',
243                 icon: 'wp_more',
244                 context: 'insert',
245                 onclick: function() {
246                         editor.execCommand( 'WP_More', 'more' );
247                 }
248         });
249
250         // Insert "Next Page"
251         editor.addMenuItem( 'wp_page', {
252                 text: 'Page break',
253                 icon: 'wp_page',
254                 context: 'insert',
255                 onclick: function() {
256                         editor.execCommand( 'WP_More', 'nextpage' );
257                 }
258         });
259
260         editor.on( 'BeforeExecCommand', function(e) {
261                 if ( tinymce.Env.webkit && ( e.command === 'InsertUnorderedList' || e.command === 'InsertOrderedList' ) ) {
262                         if ( ! style ) {
263                                 style = editor.dom.create( 'style', {'type': 'text/css'},
264                                         '#tinymce,#tinymce span,#tinymce li,#tinymce li>span,#tinymce p,#tinymce p>span{font:medium sans-serif;color:#000;line-height:normal;}');
265                         }
266
267                         editor.getDoc().head.appendChild( style );
268                 }
269         });
270
271         editor.on( 'ExecCommand', function( e ) {
272                 if ( tinymce.Env.webkit && style &&
273                         ( 'InsertUnorderedList' === e.command || 'InsertOrderedList' === e.command ) ) {
274
275                         editor.dom.remove( style );
276                 }
277         });
278
279         editor.on( 'init', function() {
280                 var env = tinymce.Env,
281                         bodyClass = ['mceContentBody'], // back-compat for themes that use this in editor-style.css...
282                         doc = editor.getDoc(),
283                         dom = editor.dom;
284
285                 if ( tinymce.Env.iOS ) {
286                         dom.addClass( doc.documentElement, 'ios' );
287                 }
288
289                 if ( editor.getParam( 'directionality' ) === 'rtl' ) {
290                         bodyClass.push('rtl');
291                         dom.setAttrib( doc.documentElement, 'dir', 'rtl' );
292                 }
293
294                 if ( env.ie ) {
295                         if ( parseInt( env.ie, 10 ) === 9 ) {
296                                 bodyClass.push('ie9');
297                         } else if ( parseInt( env.ie, 10 ) === 8 ) {
298                                 bodyClass.push('ie8');
299                         } else if ( env.ie < 8 ) {
300                                 bodyClass.push('ie7');
301                         }
302                 } else if ( env.webkit ) {
303                         bodyClass.push('webkit');
304                 }
305
306                 bodyClass.push('wp-editor');
307
308                 tinymce.each( bodyClass, function( cls ) {
309                         if ( cls ) {
310                                 dom.addClass( doc.body, cls );
311                         }
312                 });
313
314                 // Remove invalid parent paragraphs when inserting HTML
315                 // TODO: still needed?
316                 editor.on( 'BeforeSetContent', function( e ) {
317                         if ( e.content ) {
318                                 e.content = e.content.replace(/<p>\s*<(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre|address)( [^>]*)?>/gi, '<$1$2>');
319                                 e.content = e.content.replace(/<\/(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre|address)>\s*<\/p>/gi, '</$1>');
320                         }
321                 });
322
323                 if ( typeof window.jQuery !== 'undefined' ) {
324                         window.jQuery( document ).triggerHandler( 'tinymce-editor-init', [editor] );
325                 }
326
327                 if ( window.tinyMCEPreInit && window.tinyMCEPreInit.dragDropUpload ) {
328                         dom.bind( doc, 'dragstart dragend dragover drop', function( event ) {
329                                 if ( typeof window.jQuery !== 'undefined' ) {
330                                         // Trigger the jQuery handlers.
331                                         window.jQuery( document ).trigger( new window.jQuery.Event( event ) );
332                                 }
333                         });
334                 }
335
336                 if ( editor.getParam( 'wp_paste_filters', true ) ) {
337                         if ( ! tinymce.Env.webkit ) {
338                                 // In WebKit handled by removeWebKitStyles()
339                                 editor.on( 'PastePreProcess', function( event ) {
340                                         // Remove all inline styles
341                                         event.content = event.content.replace( /(<[^>]+) style="[^"]*"([^>]*>)/gi, '$1$2' );
342
343                                         // Put back the internal styles
344                                         event.content = event.content.replace(/(<[^>]+) data-mce-style=([^>]+>)/gi, '$1 style=$2' );
345                                 });
346                         }
347
348                         editor.on( 'PastePostProcess', function( event ) {
349                                 // Remove empty paragraphs
350                                 tinymce.each( dom.select( 'p', event.node ), function( node ) {
351                                         if ( dom.isEmpty( node ) ) {
352                                                 dom.remove( node );
353                                         }
354                                 });
355                         });
356                 }
357         });
358
359         // Word count
360         if ( typeof window.jQuery !== 'undefined' ) {
361                 editor.on( 'keyup', function( e ) {
362                         var key = e.keyCode || e.charCode;
363
364                         if ( key === last ) {
365                                 return;
366                         }
367
368                         if ( 13 === key || 8 === last || 46 === last ) {
369                                 window.jQuery( document ).triggerHandler( 'wpcountwords', [ editor.getContent({ format : 'raw' }) ] );
370                         }
371
372                         last = key;
373                 });
374         }
375
376         editor.on( 'SaveContent', function( e ) {
377                 // If editor is hidden, we just want the textarea's value to be saved
378                 if ( ! editor.inline && editor.isHidden() ) {
379                         e.content = e.element.value;
380                         return;
381                 }
382
383                 // Keep empty paragraphs :(
384                 e.content = e.content.replace( /<p>(?:<br ?\/?>|\u00a0|\uFEFF| )*<\/p>/g, '<p>&nbsp;</p>' );
385
386                 if ( editor.getParam( 'wpautop', true ) && typeof window.switchEditors !== 'undefined' ) {
387                         e.content = window.switchEditors.pre_wpautop( e.content );
388                 }
389         });
390
391         // Remove spaces from empty paragraphs.
392         editor.on( 'BeforeSetContent', function( event ) {
393                 if ( event.content ) {
394                         event.content = event.content.replace( /<p>(?:&nbsp;|\u00a0|\uFEFF| )+<\/p>/gi, '<p></p>' );
395                 }
396         });
397
398         editor.on( 'preInit', function() {
399                 // Don't replace <i> with <em> and <b> with <strong> and don't remove them when empty
400                 editor.schema.addValidElements( '@[id|accesskey|class|dir|lang|style|tabindex|title|contenteditable|draggable|dropzone|hidden|spellcheck|translate],i,b' );
401
402                 if ( tinymce.Env.iOS ) {
403                         editor.settings.height = 300;
404                 }
405         });
406
407         // Add custom shortcuts
408         modKey = 'alt+shift';
409
410         editor.addShortcut( modKey + '+c', '', 'JustifyCenter' );
411         editor.addShortcut( modKey + '+r', '', 'JustifyRight' );
412         editor.addShortcut( modKey + '+l', '', 'JustifyLeft' );
413         editor.addShortcut( modKey + '+j', '', 'JustifyFull' );
414         editor.addShortcut( modKey + '+q', '', 'mceBlockQuote' );
415         editor.addShortcut( modKey + '+u', '', 'InsertUnorderedList' );
416         editor.addShortcut( modKey + '+o', '', 'InsertOrderedList' );
417         editor.addShortcut( modKey + '+n', '', 'mceSpellCheck' );
418         editor.addShortcut( modKey + '+s', '', 'unlink' );
419         editor.addShortcut( modKey + '+m', '', 'WP_Medialib' );
420         editor.addShortcut( modKey + '+z', '', 'WP_Adv' );
421         editor.addShortcut( modKey + '+t', '', 'WP_More' );
422         editor.addShortcut( modKey + '+d', '', 'Strikethrough' );
423         editor.addShortcut( modKey + '+h', '', 'WP_Help' );
424         editor.addShortcut( modKey + '+p', '', 'WP_Page' );
425         editor.addShortcut( modKey + '+x', '', 'WP_Code' );
426         editor.addShortcut( 'ctrl+s', '', function() {
427                 if ( typeof wp !== 'undefined' && wp.autosave ) {
428                         wp.autosave.server.triggerSave();
429                 }
430         });
431
432         // popup buttons for the gallery, etc.
433         editor.on( 'init', function() {
434                 editor.dom.bind( editor.getWin(), 'scroll', function() {
435                         _hideButtons();
436                 });
437
438                 editor.dom.bind( editor.getBody(), 'dragstart', function() {
439                         _hideButtons();
440                 });
441         });
442
443         editor.on( 'BeforeExecCommand', function() {
444                 _hideButtons();
445         });
446
447         editor.on( 'SaveContent', function() {
448                 _hideButtons();
449         });
450
451         editor.on( 'MouseDown', function( e ) {
452                 if ( e.target.nodeName !== 'IMG' ) {
453                         _hideButtons();
454                 }
455         });
456
457         editor.on( 'keydown', function( e ) {
458                 if ( e.which === tinymce.util.VK.DELETE || e.which === tinymce.util.VK.BACKSPACE ) {
459                         _hideButtons();
460                 }
461         });
462
463         // Internal functions
464         function _setEmbed( c ) {
465                 return c.replace( /\[embed\]([\s\S]+?)\[\/embed\][\s\u00a0]*/g, function( a, b ) {
466                         return '<img width="300" height="200" src="' + tinymce.Env.transparentSrc + '" class="wp-oembed" ' +
467                                 'alt="'+ b +'" title="'+ b +'" data-mce-resize="false" data-mce-placeholder="1" />';
468                 });
469         }
470
471         function _getEmbed( c ) {
472                 return c.replace( /<img[^>]+>/g, function( a ) {
473                         if ( a.indexOf('class="wp-oembed') !== -1 ) {
474                                 var u = a.match( /alt="([^\"]+)"/ );
475
476                                 if ( u[1] ) {
477                                         a = '[embed]' + u[1] + '[/embed]';
478                                 }
479                         }
480
481                         return a;
482                 });
483         }
484
485         function _showButtons( n, id ) {
486                 var p1, p2, vp, X, Y;
487
488                 vp = editor.dom.getViewPort( editor.getWin() );
489                 p1 = DOM.getPos( editor.getContentAreaContainer() );
490                 p2 = editor.dom.getPos( n );
491
492                 X = Math.max( p2.x - vp.x, 0 ) + p1.x;
493                 Y = Math.max( p2.y - vp.y, 0 ) + p1.y;
494
495                 DOM.setStyles( id, {
496                         'top' : Y + 5 + 'px',
497                         'left' : X + 5 + 'px',
498                         'display': 'block'
499                 });
500         }
501
502         function _hideButtons() {
503                 DOM.hide( DOM.select( '#wp_editbtns, #wp_gallerybtns' ) );
504         }
505
506         // Expose some functions (back-compat)
507         return {
508                 _showButtons: _showButtons,
509                 _hideButtons: _hideButtons,
510                 _setEmbed: _setEmbed,
511                 _getEmbed: _getEmbed
512         };
513 });