]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/js/tinymce/plugins/image/plugin.js
WordPress 4.4
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / plugins / image / plugin.js
1 /**
2  * plugin.js
3  *
4  * Released under LGPL License.
5  * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
6  *
7  * License: http://www.tinymce.com/license
8  * Contributing: http://www.tinymce.com/contributing
9  */
10
11 /*global tinymce:true */
12
13 tinymce.PluginManager.add('image', function(editor) {
14         function getImageSize(url, callback) {
15                 var img = document.createElement('img');
16
17                 function done(width, height) {
18                         if (img.parentNode) {
19                                 img.parentNode.removeChild(img);
20                         }
21
22                         callback({width: width, height: height});
23                 }
24
25                 img.onload = function() {
26                         done(Math.max(img.width, img.clientWidth), Math.max(img.height, img.clientHeight));
27                 };
28
29                 img.onerror = function() {
30                         done();
31                 };
32
33                 var style = img.style;
34                 style.visibility = 'hidden';
35                 style.position = 'fixed';
36                 style.bottom = style.left = 0;
37                 style.width = style.height = 'auto';
38
39                 document.body.appendChild(img);
40                 img.src = url;
41         }
42
43         function buildListItems(inputList, itemCallback, startItems) {
44                 function appendItems(values, output) {
45                         output = output || [];
46
47                         tinymce.each(values, function(item) {
48                                 var menuItem = {text: item.text || item.title};
49
50                                 if (item.menu) {
51                                         menuItem.menu = appendItems(item.menu);
52                                 } else {
53                                         menuItem.value = item.value;
54                                         itemCallback(menuItem);
55                                 }
56
57                                 output.push(menuItem);
58                         });
59
60                         return output;
61                 }
62
63                 return appendItems(inputList, startItems || []);
64         }
65
66         function createImageList(callback) {
67                 return function() {
68                         var imageList = editor.settings.image_list;
69
70                         if (typeof imageList == "string") {
71                                 tinymce.util.XHR.send({
72                                         url: imageList,
73                                         success: function(text) {
74                                                 callback(tinymce.util.JSON.parse(text));
75                                         }
76                                 });
77                         } else if (typeof imageList == "function") {
78                                 imageList(callback);
79                         } else {
80                                 callback(imageList);
81                         }
82                 };
83         }
84
85         function showDialog(imageList) {
86                 var win, data = {}, dom = editor.dom, imgElm = editor.selection.getNode();
87                 var width, height, imageListCtrl, classListCtrl, imageDimensions = editor.settings.image_dimensions !== false;
88
89                 function recalcSize() {
90                         var widthCtrl, heightCtrl, newWidth, newHeight;
91
92                         widthCtrl = win.find('#width')[0];
93                         heightCtrl = win.find('#height')[0];
94
95                         if (!widthCtrl || !heightCtrl) {
96                                 return;
97                         }
98
99                         newWidth = widthCtrl.value();
100                         newHeight = heightCtrl.value();
101
102                         if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) {
103                                 if (width != newWidth) {
104                                         newHeight = Math.round((newWidth / width) * newHeight);
105
106                                         if (!isNaN(newHeight)) {
107                                                 heightCtrl.value(newHeight);
108                                         }
109                                 } else {
110                                         newWidth = Math.round((newHeight / height) * newWidth);
111
112                                         if (!isNaN(newWidth)) {
113                                                 widthCtrl.value(newWidth);
114                                         }
115                                 }
116                         }
117
118                         width = newWidth;
119                         height = newHeight;
120                 }
121
122                 function onSubmitForm() {
123                         function waitLoad(imgElm) {
124                                 function selectImage() {
125                                         imgElm.onload = imgElm.onerror = null;
126
127                                         if (editor.selection) {
128                                                 editor.selection.select(imgElm);
129                                                 editor.nodeChanged();
130                                         }
131                                 }
132
133                                 imgElm.onload = function() {
134                                         if (!data.width && !data.height && imageDimensions) {
135                                                 dom.setAttribs(imgElm, {
136                                                         width: imgElm.clientWidth,
137                                                         height: imgElm.clientHeight
138                                                 });
139                                                 //WP
140                                                 editor.fire( 'wpNewImageRefresh', { node: imgElm } );
141                                         }
142
143                                         selectImage();
144                                 };
145
146                                 imgElm.onerror = selectImage;
147                         }
148
149                         updateStyle();
150                         recalcSize();
151
152                         data = tinymce.extend(data, win.toJSON());
153                         var caption = data.caption; // WP
154
155                         if (!data.alt) {
156                                 data.alt = '';
157                         }
158
159                         if (!data.title) {
160                                 data.title = '';
161                         }
162
163                         if (data.width === '') {
164                                 data.width = null;
165                         }
166
167                         if (data.height === '') {
168                                 data.height = null;
169                         }
170
171                         if (!data.style) {
172                                 data.style = null;
173                         }
174
175                         // Setup new data excluding style properties
176                         /*eslint dot-notation: 0*/
177                         data = {
178                                 src: data.src,
179                                 alt: data.alt,
180                                 title: data.title,
181                                 width: data.width,
182                                 height: data.height,
183                                 style: data.style,
184                                 "class": data["class"]
185                         };
186
187                         editor.undoManager.transact(function() {
188                                 // WP
189                                 var eventData = { node: imgElm, data: data, caption: caption };
190
191                                 editor.fire( 'wpImageFormSubmit', { imgData: eventData } );
192
193                                 if ( eventData.cancel ) {
194                                         waitLoad( eventData.node );
195                                         return;
196                                 }
197                                 // WP end
198
199                                 if (!data.src) {
200                                         if (imgElm) {
201                                                 dom.remove(imgElm);
202                                                 editor.focus();
203                                                 editor.nodeChanged();
204                                         }
205
206                                         return;
207                                 }
208
209                                 if (data.title === "") {
210                                         data.title = null;
211                                 }
212
213                                 if (!imgElm) {
214                                         data.id = '__mcenew';
215                                         editor.focus();
216                                         editor.selection.setContent(dom.createHTML('img', data));
217                                         imgElm = dom.get('__mcenew');
218                                         dom.setAttrib(imgElm, 'id', null);
219                                 } else {
220                                         dom.setAttribs(imgElm, data);
221                                         editor.editorUpload.uploadImagesAuto();
222                                 }
223
224                                 waitLoad(imgElm);
225                         });
226                 }
227
228                 function removePixelSuffix(value) {
229                         if (value) {
230                                 value = value.replace(/px$/, '');
231                         }
232
233                         return value;
234                 }
235
236                 function srcChange(e) {
237                         var srcURL, prependURL, absoluteURLPattern, meta = e.meta || {};
238
239                         if (imageListCtrl) {
240                                 imageListCtrl.value(editor.convertURL(this.value(), 'src'));
241                         }
242
243                         tinymce.each(meta, function(value, key) {
244                                 win.find('#' + key).value(value);
245                         });
246
247                         if (!meta.width && !meta.height) {
248                                 srcURL = editor.convertURL(this.value(), 'src');
249
250                                 // Pattern test the src url and make sure we haven't already prepended the url
251                                 prependURL = editor.settings.image_prepend_url;
252                                 absoluteURLPattern = new RegExp('^(?:[a-z]+:)?//', 'i');
253                                 if (prependURL && !absoluteURLPattern.test(srcURL) && srcURL.substring(0, prependURL.length) !== prependURL) {
254                                         srcURL = prependURL + srcURL;
255                                 }
256
257                                 this.value(srcURL);
258
259                                 getImageSize(editor.documentBaseURI.toAbsolute(this.value()), function(data) {
260                                         if (data.width && data.height && imageDimensions) {
261                                                 width = data.width;
262                                                 height = data.height;
263
264                                                 win.find('#width').value(width);
265                                                 win.find('#height').value(height);
266                                         }
267                                 });
268                         }
269                 }
270
271                 width = dom.getAttrib(imgElm, 'width');
272                 height = dom.getAttrib(imgElm, 'height');
273
274                 if (imgElm.nodeName == 'IMG' && !imgElm.getAttribute('data-mce-object') && !imgElm.getAttribute('data-mce-placeholder')) {
275                         data = {
276                                 src: dom.getAttrib(imgElm, 'src'),
277                                 alt: dom.getAttrib(imgElm, 'alt'),
278                                 title: dom.getAttrib(imgElm, 'title'),
279                                 "class": dom.getAttrib(imgElm, 'class'),
280                                 width: width,
281                                 height: height
282                         };
283
284                         // WP
285                         editor.fire( 'wpLoadImageData', { imgData: { data: data, node: imgElm } } );
286                 } else {
287                         imgElm = null;
288                 }
289
290                 if (imageList) {
291                         imageListCtrl = {
292                                 type: 'listbox',
293                                 label: 'Image list',
294                                 values: buildListItems(
295                                         imageList,
296                                         function(item) {
297                                                 item.value = editor.convertURL(item.value || item.url, 'src');
298                                         },
299                                         [{text: 'None', value: ''}]
300                                 ),
301                                 value: data.src && editor.convertURL(data.src, 'src'),
302                                 onselect: function(e) {
303                                         var altCtrl = win.find('#alt');
304
305                                         if (!altCtrl.value() || (e.lastControl && altCtrl.value() == e.lastControl.text())) {
306                                                 altCtrl.value(e.control.text());
307                                         }
308
309                                         win.find('#src').value(e.control.value()).fire('change');
310                                 },
311                                 onPostRender: function() {
312                                         /*eslint consistent-this: 0*/
313                                         imageListCtrl = this;
314                                 }
315                         };
316                 }
317
318                 if (editor.settings.image_class_list) {
319                         classListCtrl = {
320                                 name: 'class',
321                                 type: 'listbox',
322                                 label: 'Class',
323                                 values: buildListItems(
324                                         editor.settings.image_class_list,
325                                         function(item) {
326                                                 if (item.value) {
327                                                         item.textStyle = function() {
328                                                                 return editor.formatter.getCssText({inline: 'img', classes: [item.value]});
329                                                         };
330                                                 }
331                                         }
332                                 )
333                         };
334                 }
335
336                 // General settings shared between simple and advanced dialogs
337                 var generalFormItems = [
338                         {
339                                 name: 'src',
340                                 type: 'filepicker',
341                                 filetype: 'image',
342                                 label: 'Source',
343                                 autofocus: true,
344                                 onchange: srcChange
345                         },
346                         imageListCtrl
347                 ];
348
349                 if (editor.settings.image_description !== false) {
350                         generalFormItems.push({name: 'alt', type: 'textbox', label: 'Image description'});
351                 }
352
353                 if (editor.settings.image_title) {
354                         generalFormItems.push({name: 'title', type: 'textbox', label: 'Image Title'});
355                 }
356
357                 if (imageDimensions) {
358                         generalFormItems.push({
359                                 type: 'container',
360                                 label: 'Dimensions',
361                                 layout: 'flex',
362                                 direction: 'row',
363                                 align: 'center',
364                                 spacing: 5,
365                                 items: [
366                                         {name: 'width', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Width'},
367                                         {type: 'label', text: 'x'},
368                                         {name: 'height', type: 'textbox', maxLength: 5, size: 3, onchange: recalcSize, ariaLabel: 'Height'},
369                                         {name: 'constrain', type: 'checkbox', checked: true, text: 'Constrain proportions'}
370                                 ]
371                         });
372                 }
373
374                 generalFormItems.push(classListCtrl);
375
376                 // WP
377                 editor.fire( 'wpLoadImageForm', { data: generalFormItems } );
378
379                 function mergeMargins(css) {
380                         if (css.margin) {
381
382                                 var splitMargin = css.margin.split(" ");
383
384                                 switch (splitMargin.length) {
385                                         case 1: //margin: toprightbottomleft;
386                                                 css['margin-top'] = css['margin-top'] || splitMargin[0];
387                                                 css['margin-right'] = css['margin-right'] || splitMargin[0];
388                                                 css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
389                                                 css['margin-left'] = css['margin-left'] || splitMargin[0];
390                                                 break;
391                                         case 2: //margin: topbottom rightleft;
392                                                 css['margin-top'] = css['margin-top'] || splitMargin[0];
393                                                 css['margin-right'] = css['margin-right'] || splitMargin[1];
394                                                 css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
395                                                 css['margin-left'] = css['margin-left'] || splitMargin[1];
396                                                 break;
397                                         case 3: //margin: top rightleft bottom;
398                                                 css['margin-top'] = css['margin-top'] || splitMargin[0];
399                                                 css['margin-right'] = css['margin-right'] || splitMargin[1];
400                                                 css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
401                                                 css['margin-left'] = css['margin-left'] || splitMargin[1];
402                                                 break;
403                                         case 4: //margin: top right bottom left;
404                                                 css['margin-top'] = css['margin-top'] || splitMargin[0];
405                                                 css['margin-right'] = css['margin-right'] || splitMargin[1];
406                                                 css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
407                                                 css['margin-left'] = css['margin-left'] || splitMargin[3];
408                                 }
409                                 delete css.margin;
410                         }
411                         return css;
412                 }
413
414                 function updateStyle() {
415                         function addPixelSuffix(value) {
416                                 if (value.length > 0 && /^[0-9]+$/.test(value)) {
417                                         value += 'px';
418                                 }
419
420                                 return value;
421                         }
422
423                         if (!editor.settings.image_advtab) {
424                                 return;
425                         }
426
427                         var data = win.toJSON(),
428                                 css = dom.parseStyle(data.style);
429
430                         css = mergeMargins(css);
431
432                         if (data.vspace) {
433                                 css['margin-top'] = css['margin-bottom'] = addPixelSuffix(data.vspace);
434                         }
435                         if (data.hspace) {
436                                 css['margin-left'] = css['margin-right'] = addPixelSuffix(data.hspace);
437                         }
438                         if (data.border) {
439                                 css['border-width'] = addPixelSuffix(data.border);
440                         }
441
442                         win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
443                 }
444
445                 function updateVSpaceHSpaceBorder() {
446                         if (!editor.settings.image_advtab) {
447                                 return;
448                         }
449
450                         var data = win.toJSON(),
451                                 css = dom.parseStyle(data.style);
452
453                         win.find('#vspace').value("");
454                         win.find('#hspace').value("");
455
456                         css = mergeMargins(css);
457
458                         //Move opposite equal margins to vspace/hspace field
459                         if ((css['margin-top'] && css['margin-bottom']) || (css['margin-right'] && css['margin-left'])) {
460                                 if (css['margin-top'] === css['margin-bottom']) {
461                                         win.find('#vspace').value(removePixelSuffix(css['margin-top']));
462                                 } else {
463                                         win.find('#vspace').value('');
464                                 }
465                                 if (css['margin-right'] === css['margin-left']) {
466                                         win.find('#hspace').value(removePixelSuffix(css['margin-right']));
467                                 } else {
468                                         win.find('#hspace').value('');
469                                 }
470                         }
471
472                         //Move border-width
473                         if (css['border-width']) {
474                                 win.find('#border').value(removePixelSuffix(css['border-width']));
475                         }
476
477                         win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
478
479                 }
480
481                 if (editor.settings.image_advtab) {
482                         // Parse styles from img
483                         if (imgElm) {
484                                 if (imgElm.style.marginLeft && imgElm.style.marginRight && imgElm.style.marginLeft === imgElm.style.marginRight) {
485                                         data.hspace = removePixelSuffix(imgElm.style.marginLeft);
486                                 }
487                                 if (imgElm.style.marginTop && imgElm.style.marginBottom && imgElm.style.marginTop === imgElm.style.marginBottom) {
488                                         data.vspace = removePixelSuffix(imgElm.style.marginTop);
489                                 }
490                                 if (imgElm.style.borderWidth) {
491                                         data.border = removePixelSuffix(imgElm.style.borderWidth);
492                                 }
493
494                                 data.style = editor.dom.serializeStyle(editor.dom.parseStyle(editor.dom.getAttrib(imgElm, 'style')));
495                         }
496
497                         // Advanced dialog shows general+advanced tabs
498                         win = editor.windowManager.open({
499                                 title: 'Insert/edit image',
500                                 data: data,
501                                 bodyType: 'tabpanel',
502                                 body: [
503                                         {
504                                                 title: 'General',
505                                                 type: 'form',
506                                                 items: generalFormItems
507                                         },
508
509                                         {
510                                                 title: 'Advanced',
511                                                 type: 'form',
512                                                 pack: 'start',
513                                                 items: [
514                                                         {
515                                                                 label: 'Style',
516                                                                 name: 'style',
517                                                                 type: 'textbox',
518                                                                 onchange: updateVSpaceHSpaceBorder
519                                                         },
520                                                         {
521                                                                 type: 'form',
522                                                                 layout: 'grid',
523                                                                 packV: 'start',
524                                                                 columns: 2,
525                                                                 padding: 0,
526                                                                 alignH: ['left', 'right'],
527                                                                 defaults: {
528                                                                         type: 'textbox',
529                                                                         maxWidth: 50,
530                                                                         onchange: updateStyle
531                                                                 },
532                                                                 items: [
533                                                                         {label: 'Vertical space', name: 'vspace'},
534                                                                         {label: 'Horizontal space', name: 'hspace'},
535                                                                         {label: 'Border', name: 'border'}
536                                                                 ]
537                                                         }
538                                                 ]
539                                         }
540                                 ],
541                                 onSubmit: onSubmitForm
542                         });
543                 } else {
544                         // Simple default dialog
545                         win = editor.windowManager.open({
546                                 title: 'Insert/edit image',
547                                 data: data,
548                                 body: generalFormItems,
549                                 onSubmit: onSubmitForm
550                         });
551                 }
552         }
553
554         editor.addButton('image', {
555                 icon: 'image',
556                 tooltip: 'Insert/edit image',
557                 onclick: createImageList(showDialog),
558                 stateSelector: 'img:not([data-mce-object],[data-mce-placeholder])'
559         });
560
561         editor.addMenuItem('image', {
562                 icon: 'image',
563                 text: 'Insert/edit image',
564                 onclick: createImageList(showDialog),
565                 context: 'insert',
566                 prependToContext: true
567         });
568
569         editor.addCommand('mceImage', createImageList(showDialog));
570 });