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