1(function () {
2var image = (function (domGlobals) {
3 'use strict';
4
5 var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
6
7 var hasDimensions = function (editor) {
8 return editor.settings.image_dimensions === false ? false : true;
9 };
10 var hasAdvTab = function (editor) {
11 return editor.settings.image_advtab === true ? true : false;
12 };
13 var getPrependUrl = function (editor) {
14 return editor.getParam('image_prepend_url', '');
15 };
16 var getClassList = function (editor) {
17 return editor.getParam('image_class_list');
18 };
19 var hasDescription = function (editor) {
20 return editor.settings.image_description === false ? false : true;
21 };
22 var hasImageTitle = function (editor) {
23 return editor.settings.image_title === true ? true : false;
24 };
25 var hasImageCaption = function (editor) {
26 return editor.settings.image_caption === true ? true : false;
27 };
28 var getImageList = function (editor) {
29 return editor.getParam('image_list', false);
30 };
31 var hasUploadUrl = function (editor) {
32 return editor.getParam('images_upload_url', false);
33 };
34 var hasUploadHandler = function (editor) {
35 return editor.getParam('images_upload_handler', false);
36 };
37 var getUploadUrl = function (editor) {
38 return editor.getParam('images_upload_url');
39 };
40 var getUploadHandler = function (editor) {
41 return editor.getParam('images_upload_handler');
42 };
43 var getUploadBasePath = function (editor) {
44 return editor.getParam('images_upload_base_path');
45 };
46 var getUploadCredentials = function (editor) {
47 return editor.getParam('images_upload_credentials');
48 };
49 var Settings = {
50 hasDimensions: hasDimensions,
51 hasAdvTab: hasAdvTab,
52 getPrependUrl: getPrependUrl,
53 getClassList: getClassList,
54 hasDescription: hasDescription,
55 hasImageTitle: hasImageTitle,
56 hasImageCaption: hasImageCaption,
57 getImageList: getImageList,
58 hasUploadUrl: hasUploadUrl,
59 hasUploadHandler: hasUploadHandler,
60 getUploadUrl: getUploadUrl,
61 getUploadHandler: getUploadHandler,
62 getUploadBasePath: getUploadBasePath,
63 getUploadCredentials: getUploadCredentials
64 };
65
66 var Global = typeof domGlobals.window !== 'undefined' ? domGlobals.window : Function('return this;')();
67
68 var path = function (parts, scope) {
69 var o = scope !== undefined && scope !== null ? scope : Global;
70 for (var i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
71 o = o[parts[i]];
72 }
73 return o;
74 };
75 var resolve = function (p, scope) {
76 var parts = p.split('.');
77 return path(parts, scope);
78 };
79
80 var unsafe = function (name, scope) {
81 return resolve(name, scope);
82 };
83 var getOrDie = function (name, scope) {
84 var actual = unsafe(name, scope);
85 if (actual === undefined || actual === null) {
86 throw new Error(name + ' not available on this browser');
87 }
88 return actual;
89 };
90 var Global$1 = { getOrDie: getOrDie };
91
92 function FileReader () {
93 var f = Global$1.getOrDie('FileReader');
94 return new f();
95 }
96
97 var global$1 = tinymce.util.Tools.resolve('tinymce.util.Promise');
98
99 var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
100
101 var global$3 = tinymce.util.Tools.resolve('tinymce.util.XHR');
102
103 var parseIntAndGetMax = function (val1, val2) {
104 return Math.max(parseInt(val1, 10), parseInt(val2, 10));
105 };
106 var getImageSize = function (url, callback) {
107 var img = domGlobals.document.createElement('img');
108 function done(width, height) {
109 if (img.parentNode) {
110 img.parentNode.removeChild(img);
111 }
112 callback({
113 width: width,
114 height: height
115 });
116 }
117 img.onload = function () {
118 var width = parseIntAndGetMax(img.width, img.clientWidth);
119 var height = parseIntAndGetMax(img.height, img.clientHeight);
120 done(width, height);
121 };
122 img.onerror = function () {
123 done(0, 0);
124 };
125 var style = img.style;
126 style.visibility = 'hidden';
127 style.position = 'fixed';
128 style.bottom = style.left = '0px';
129 style.width = style.height = 'auto';
130 domGlobals.document.body.appendChild(img);
131 img.src = url;
132 };
133 var buildListItems = function (inputList, itemCallback, startItems) {
134 function appendItems(values, output) {
135 output = output || [];
136 global$2.each(values, function (item) {
137 var menuItem = { text: item.text || item.title };
138 if (item.menu) {
139 menuItem.menu = appendItems(item.menu);
140 } else {
141 menuItem.value = item.value;
142 itemCallback(menuItem);
143 }
144 output.push(menuItem);
145 });
146 return output;
147 }
148 return appendItems(inputList, startItems || []);
149 };
150 var removePixelSuffix = function (value) {
151 if (value) {
152 value = value.replace(/px$/, '');
153 }
154 return value;
155 };
156 var addPixelSuffix = function (value) {
157 if (value.length > 0 && /^[0-9]+$/.test(value)) {
158 value += 'px';
159 }
160 return value;
161 };
162 var mergeMargins = function (css) {
163 if (css.margin) {
164 var splitMargin = css.margin.split(' ');
165 switch (splitMargin.length) {
166 case 1:
167 css['margin-top'] = css['margin-top'] || splitMargin[0];
168 css['margin-right'] = css['margin-right'] || splitMargin[0];
169 css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
170 css['margin-left'] = css['margin-left'] || splitMargin[0];
171 break;
172 case 2:
173 css['margin-top'] = css['margin-top'] || splitMargin[0];
174 css['margin-right'] = css['margin-right'] || splitMargin[1];
175 css['margin-bottom'] = css['margin-bottom'] || splitMargin[0];
176 css['margin-left'] = css['margin-left'] || splitMargin[1];
177 break;
178 case 3:
179 css['margin-top'] = css['margin-top'] || splitMargin[0];
180 css['margin-right'] = css['margin-right'] || splitMargin[1];
181 css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
182 css['margin-left'] = css['margin-left'] || splitMargin[1];
183 break;
184 case 4:
185 css['margin-top'] = css['margin-top'] || splitMargin[0];
186 css['margin-right'] = css['margin-right'] || splitMargin[1];
187 css['margin-bottom'] = css['margin-bottom'] || splitMargin[2];
188 css['margin-left'] = css['margin-left'] || splitMargin[3];
189 }
190 delete css.margin;
191 }
192 return css;
193 };
194 var createImageList = function (editor, callback) {
195 var imageList = Settings.getImageList(editor);
196 if (typeof imageList === 'string') {
197 global$3.send({
198 url: imageList,
199 success: function (text) {
200 callback(JSON.parse(text));
201 }
202 });
203 } else if (typeof imageList === 'function') {
204 imageList(callback);
205 } else {
206 callback(imageList);
207 }
208 };
209 var waitLoadImage = function (editor, data, imgElm) {
210 function selectImage() {
211 imgElm.onload = imgElm.onerror = null;
212 if (editor.selection) {
213 editor.selection.select(imgElm);
214 editor.nodeChanged();
215 }
216 }
217 imgElm.onload = function () {
218 if (!data.width && !data.height && Settings.hasDimensions(editor)) {
219 editor.dom.setAttribs(imgElm, {
220 width: imgElm.clientWidth,
221 height: imgElm.clientHeight
222 });
223 }
224 selectImage();
225 };
226 imgElm.onerror = selectImage;
227 };
228 var blobToDataUri = function (blob) {
229 return new global$1(function (resolve, reject) {
230 var reader = FileReader();
231 reader.onload = function () {
232 resolve(reader.result);
233 };
234 reader.onerror = function () {
235 reject(reader.error.message);
236 };
237 reader.readAsDataURL(blob);
238 });
239 };
240 var Utils = {
241 getImageSize: getImageSize,
242 buildListItems: buildListItems,
243 removePixelSuffix: removePixelSuffix,
244 addPixelSuffix: addPixelSuffix,
245 mergeMargins: mergeMargins,
246 createImageList: createImageList,
247 waitLoadImage: waitLoadImage,
248 blobToDataUri: blobToDataUri
249 };
250
251 var global$4 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
252
253 var hasOwnProperty = Object.prototype.hasOwnProperty;
254 var shallow = function (old, nu) {
255 return nu;
256 };
257 var baseMerge = function (merger) {
258 return function () {
259 var objects = new Array(arguments.length);
260 for (var i = 0; i < objects.length; i++) {
261 objects[i] = arguments[i];
262 }
263 if (objects.length === 0) {
264 throw new Error('Can\'t merge zero objects');
265 }
266 var ret = {};
267 for (var j = 0; j < objects.length; j++) {
268 var curObject = objects[j];
269 for (var key in curObject) {
270 if (hasOwnProperty.call(curObject, key)) {
271 ret[key] = merger(ret[key], curObject[key]);
272 }
273 }
274 }
275 return ret;
276 };
277 };
278 var merge = baseMerge(shallow);
279
280 var DOM = global$4.DOM;
281 var getHspace = function (image) {
282 if (image.style.marginLeft && image.style.marginRight && image.style.marginLeft === image.style.marginRight) {
283 return Utils.removePixelSuffix(image.style.marginLeft);
284 } else {
285 return '';
286 }
287 };
288 var getVspace = function (image) {
289 if (image.style.marginTop && image.style.marginBottom && image.style.marginTop === image.style.marginBottom) {
290 return Utils.removePixelSuffix(image.style.marginTop);
291 } else {
292 return '';
293 }
294 };
295 var getBorder = function (image) {
296 if (image.style.borderWidth) {
297 return Utils.removePixelSuffix(image.style.borderWidth);
298 } else {
299 return '';
300 }
301 };
302 var getAttrib = function (image, name) {
303 if (image.hasAttribute(name)) {
304 return image.getAttribute(name);
305 } else {
306 return '';
307 }
308 };
309 var getStyle = function (image, name) {
310 return image.style[name] ? image.style[name] : '';
311 };
312 var hasCaption = function (image) {
313 return image.parentNode !== null && image.parentNode.nodeName === 'FIGURE';
314 };
315 var setAttrib = function (image, name, value) {
316 image.setAttribute(name, value);
317 };
318 var wrapInFigure = function (image) {
319 var figureElm = DOM.create('figure', { class: 'image' });
320 DOM.insertAfter(figureElm, image);
321 figureElm.appendChild(image);
322 figureElm.appendChild(DOM.create('figcaption', { contentEditable: true }, 'Caption'));
323 figureElm.contentEditable = 'false';
324 };
325 var removeFigure = function (image) {
326 var figureElm = image.parentNode;
327 DOM.insertAfter(image, figureElm);
328 DOM.remove(figureElm);
329 };
330 var toggleCaption = function (image) {
331 if (hasCaption(image)) {
332 removeFigure(image);
333 } else {
334 wrapInFigure(image);
335 }
336 };
337 var normalizeStyle = function (image, normalizeCss) {
338 var attrValue = image.getAttribute('style');
339 var value = normalizeCss(attrValue !== null ? attrValue : '');
340 if (value.length > 0) {
341 image.setAttribute('style', value);
342 image.setAttribute('data-mce-style', value);
343 } else {
344 image.removeAttribute('style');
345 }
346 };
347 var setSize = function (name, normalizeCss) {
348 return function (image, name, value) {
349 if (image.style[name]) {
350 image.style[name] = Utils.addPixelSuffix(value);
351 normalizeStyle(image, normalizeCss);
352 } else {
353 setAttrib(image, name, value);
354 }
355 };
356 };
357 var getSize = function (image, name) {
358 if (image.style[name]) {
359 return Utils.removePixelSuffix(image.style[name]);
360 } else {
361 return getAttrib(image, name);
362 }
363 };
364 var setHspace = function (image, value) {
365 var pxValue = Utils.addPixelSuffix(value);
366 image.style.marginLeft = pxValue;
367 image.style.marginRight = pxValue;
368 };
369 var setVspace = function (image, value) {
370 var pxValue = Utils.addPixelSuffix(value);
371 image.style.marginTop = pxValue;
372 image.style.marginBottom = pxValue;
373 };
374 var setBorder = function (image, value) {
375 var pxValue = Utils.addPixelSuffix(value);
376 image.style.borderWidth = pxValue;
377 };
378 var setBorderStyle = function (image, value) {
379 image.style.borderStyle = value;
380 };
381 var getBorderStyle = function (image) {
382 return getStyle(image, 'borderStyle');
383 };
384 var isFigure = function (elm) {
385 return elm.nodeName === 'FIGURE';
386 };
387 var defaultData = function () {
388 return {
389 src: '',
390 alt: '',
391 title: '',
392 width: '',
393 height: '',
394 class: '',
395 style: '',
396 caption: false,
397 hspace: '',
398 vspace: '',
399 border: '',
400 borderStyle: ''
401 };
402 };
403 var getStyleValue = function (normalizeCss, data) {
404 var image = domGlobals.document.createElement('img');
405 setAttrib(image, 'style', data.style);
406 if (getHspace(image) || data.hspace !== '') {
407 setHspace(image, data.hspace);
408 }
409 if (getVspace(image) || data.vspace !== '') {
410 setVspace(image, data.vspace);
411 }
412 if (getBorder(image) || data.border !== '') {
413 setBorder(image, data.border);
414 }
415 if (getBorderStyle(image) || data.borderStyle !== '') {
416 setBorderStyle(image, data.borderStyle);
417 }
418 return normalizeCss(image.getAttribute('style'));
419 };
420 var create = function (normalizeCss, data) {
421 var image = domGlobals.document.createElement('img');
422 write(normalizeCss, merge(data, { caption: false }), image);
423 setAttrib(image, 'alt', data.alt);
424 if (data.caption) {
425 var figure = DOM.create('figure', { class: 'image' });
426 figure.appendChild(image);
427 figure.appendChild(DOM.create('figcaption', { contentEditable: true }, 'Caption'));
428 figure.contentEditable = 'false';
429 return figure;
430 } else {
431 return image;
432 }
433 };
434 var read = function (normalizeCss, image) {
435 return {
436 src: getAttrib(image, 'src'),
437 alt: getAttrib(image, 'alt'),
438 title: getAttrib(image, 'title'),
439 width: getSize(image, 'width'),
440 height: getSize(image, 'height'),
441 class: getAttrib(image, 'class'),
442 style: normalizeCss(getAttrib(image, 'style')),
443 caption: hasCaption(image),
444 hspace: getHspace(image),
445 vspace: getVspace(image),
446 border: getBorder(image),
447 borderStyle: getStyle(image, 'borderStyle')
448 };
449 };
450 var updateProp = function (image, oldData, newData, name, set) {
451 if (newData[name] !== oldData[name]) {
452 set(image, name, newData[name]);
453 }
454 };
455 var normalized = function (set, normalizeCss) {
456 return function (image, name, value) {
457 set(image, value);
458 normalizeStyle(image, normalizeCss);
459 };
460 };
461 var write = function (normalizeCss, newData, image) {
462 var oldData = read(normalizeCss, image);
463 updateProp(image, oldData, newData, 'caption', function (image, _name, _value) {
464 return toggleCaption(image);
465 });
466 updateProp(image, oldData, newData, 'src', setAttrib);
467 updateProp(image, oldData, newData, 'alt', setAttrib);
468 updateProp(image, oldData, newData, 'title', setAttrib);
469 updateProp(image, oldData, newData, 'width', setSize('width', normalizeCss));
470 updateProp(image, oldData, newData, 'height', setSize('height', normalizeCss));
471 updateProp(image, oldData, newData, 'class', setAttrib);
472 updateProp(image, oldData, newData, 'style', normalized(function (image, value) {
473 return setAttrib(image, 'style', value);
474 }, normalizeCss));
475 updateProp(image, oldData, newData, 'hspace', normalized(setHspace, normalizeCss));
476 updateProp(image, oldData, newData, 'vspace', normalized(setVspace, normalizeCss));
477 updateProp(image, oldData, newData, 'border', normalized(setBorder, normalizeCss));
478 updateProp(image, oldData, newData, 'borderStyle', normalized(setBorderStyle, normalizeCss));
479 };
480
481 var normalizeCss = function (editor, cssText) {
482 var css = editor.dom.styles.parse(cssText);
483 var mergedCss = Utils.mergeMargins(css);
484 var compressed = editor.dom.styles.parse(editor.dom.styles.serialize(mergedCss));
485 return editor.dom.styles.serialize(compressed);
486 };
487 var getSelectedImage = function (editor) {
488 var imgElm = editor.selection.getNode();
489 var figureElm = editor.dom.getParent(imgElm, 'figure.image');
490 if (figureElm) {
491 return editor.dom.select('img', figureElm)[0];
492 }
493 if (imgElm && (imgElm.nodeName !== 'IMG' || imgElm.getAttribute('data-mce-object') || imgElm.getAttribute('data-mce-placeholder'))) {
494 return null;
495 }
496 return imgElm;
497 };
498 var splitTextBlock = function (editor, figure) {
499 var dom = editor.dom;
500 var textBlock = dom.getParent(figure.parentNode, function (node) {
501 return editor.schema.getTextBlockElements()[node.nodeName];
502 }, editor.getBody());
503 if (textBlock) {
504 return dom.split(textBlock, figure);
505 } else {
506 return figure;
507 }
508 };
509 var readImageDataFromSelection = function (editor) {
510 var image = getSelectedImage(editor);
511 return image ? read(function (css) {
512 return normalizeCss(editor, css);
513 }, image) : defaultData();
514 };
515 var insertImageAtCaret = function (editor, data) {
516 var elm = create(function (css) {
517 return normalizeCss(editor, css);
518 }, data);
519 editor.dom.setAttrib(elm, 'data-mce-id', '__mcenew');
520 editor.focus();
521 editor.selection.setContent(elm.outerHTML);
522 var insertedElm = editor.dom.select('*[data-mce-id="__mcenew"]')[0];
523 editor.dom.setAttrib(insertedElm, 'data-mce-id', null);
524 if (isFigure(insertedElm)) {
525 var figure = splitTextBlock(editor, insertedElm);
526 editor.selection.select(figure);
527 } else {
528 editor.selection.select(insertedElm);
529 }
530 };
531 var syncSrcAttr = function (editor, image) {
532 editor.dom.setAttrib(image, 'src', image.getAttribute('src'));
533 };
534 var deleteImage = function (editor, image) {
535 if (image) {
536 var elm = editor.dom.is(image.parentNode, 'figure.image') ? image.parentNode : image;
537 editor.dom.remove(elm);
538 editor.focus();
539 editor.nodeChanged();
540 if (editor.dom.isEmpty(editor.getBody())) {
541 editor.setContent('');
542 editor.selection.setCursorLocation();
543 }
544 }
545 };
546 var writeImageDataToSelection = function (editor, data) {
547 var image = getSelectedImage(editor);
548 write(function (css) {
549 return normalizeCss(editor, css);
550 }, data, image);
551 syncSrcAttr(editor, image);
552 if (isFigure(image.parentNode)) {
553 var figure = image.parentNode;
554 splitTextBlock(editor, figure);
555 editor.selection.select(image.parentNode);
556 } else {
557 editor.selection.select(image);
558 Utils.waitLoadImage(editor, data, image);
559 }
560 };
561 var insertOrUpdateImage = function (editor, data) {
562 var image = getSelectedImage(editor);
563 if (image) {
564 if (data.src) {
565 writeImageDataToSelection(editor, data);
566 } else {
567 deleteImage(editor, image);
568 }
569 } else if (data.src) {
570 insertImageAtCaret(editor, data);
571 }
572 };
573
574 var updateVSpaceHSpaceBorder = function (editor) {
575 return function (evt) {
576 var dom = editor.dom;
577 var rootControl = evt.control.rootControl;
578 if (!Settings.hasAdvTab(editor)) {
579 return;
580 }
581 var data = rootControl.toJSON();
582 var css = dom.parseStyle(data.style);
583 rootControl.find('#vspace').value('');
584 rootControl.find('#hspace').value('');
585 css = Utils.mergeMargins(css);
586 if (css['margin-top'] && css['margin-bottom'] || css['margin-right'] && css['margin-left']) {
587 if (css['margin-top'] === css['margin-bottom']) {
588 rootControl.find('#vspace').value(Utils.removePixelSuffix(css['margin-top']));
589 } else {
590 rootControl.find('#vspace').value('');
591 }
592 if (css['margin-right'] === css['margin-left']) {
593 rootControl.find('#hspace').value(Utils.removePixelSuffix(css['margin-right']));
594 } else {
595 rootControl.find('#hspace').value('');
596 }
597 }
598 if (css['border-width']) {
599 rootControl.find('#border').value(Utils.removePixelSuffix(css['border-width']));
600 } else {
601 rootControl.find('#border').value('');
602 }
603 if (css['border-style']) {
604 rootControl.find('#borderStyle').value(css['border-style']);
605 } else {
606 rootControl.find('#borderStyle').value('');
607 }
608 rootControl.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
609 };
610 };
611 var updateStyle = function (editor, win) {
612 win.find('#style').each(function (ctrl) {
613 var value = getStyleValue(function (css) {
614 return normalizeCss(editor, css);
615 }, merge(defaultData(), win.toJSON()));
616 ctrl.value(value);
617 });
618 };
619 var makeTab = function (editor) {
620 return {
621 title: 'Advanced',
622 type: 'form',
623 pack: 'start',
624 items: [
625 {
626 label: 'Style',
627 name: 'style',
628 type: 'textbox',
629 onchange: updateVSpaceHSpaceBorder(editor)
630 },
631 {
632 type: 'form',
633 layout: 'grid',
634 packV: 'start',
635 columns: 2,
636 padding: 0,
637 defaults: {
638 type: 'textbox',
639 maxWidth: 50,
640 onchange: function (evt) {
641 updateStyle(editor, evt.control.rootControl);
642 }
643 },
644 items: [
645 {
646 label: 'Vertical space',
647 name: 'vspace'
648 },
649 {
650 label: 'Border width',
651 name: 'border'
652 },
653 {
654 label: 'Horizontal space',
655 name: 'hspace'
656 },
657 {
658 label: 'Border style',
659 type: 'listbox',
660 name: 'borderStyle',
661 width: 90,
662 maxWidth: 90,
663 onselect: function (evt) {
664 updateStyle(editor, evt.control.rootControl);
665 },
666 values: [
667 {
668 text: 'Select...',
669 value: ''
670 },
671 {
672 text: 'Solid',
673 value: 'solid'
674 },
675 {
676 text: 'Dotted',
677 value: 'dotted'
678 },
679 {
680 text: 'Dashed',
681 value: 'dashed'
682 },
683 {
684 text: 'Double',
685 value: 'double'
686 },
687 {
688 text: 'Groove',
689 value: 'groove'
690 },
691 {
692 text: 'Ridge',
693 value: 'ridge'
694 },
695 {
696 text: 'Inset',
697 value: 'inset'
698 },
699 {
700 text: 'Outset',
701 value: 'outset'
702 },
703 {
704 text: 'None',
705 value: 'none'
706 },
707 {
708 text: 'Hidden',
709 value: 'hidden'
710 }
711 ]
712 }
713 ]
714 }
715 ]
716 };
717 };
718 var AdvTab = { makeTab: makeTab };
719
720 var doSyncSize = function (widthCtrl, heightCtrl) {
721 widthCtrl.state.set('oldVal', widthCtrl.value());
722 heightCtrl.state.set('oldVal', heightCtrl.value());
723 };
724 var doSizeControls = function (win, f) {
725 var widthCtrl = win.find('#width')[0];
726 var heightCtrl = win.find('#height')[0];
727 var constrained = win.find('#constrain')[0];
728 if (widthCtrl && heightCtrl && constrained) {
729 f(widthCtrl, heightCtrl, constrained.checked());
730 }
731 };
732 var doUpdateSize = function (widthCtrl, heightCtrl, isContrained) {
733 var oldWidth = widthCtrl.state.get('oldVal');
734 var oldHeight = heightCtrl.state.get('oldVal');
735 var newWidth = widthCtrl.value();
736 var newHeight = heightCtrl.value();
737 if (isContrained && oldWidth && oldHeight && newWidth && newHeight) {
738 if (newWidth !== oldWidth) {
739 newHeight = Math.round(newWidth / oldWidth * newHeight);
740 if (!isNaN(newHeight)) {
741 heightCtrl.value(newHeight);
742 }
743 } else {
744 newWidth = Math.round(newHeight / oldHeight * newWidth);
745 if (!isNaN(newWidth)) {
746 widthCtrl.value(newWidth);
747 }
748 }
749 }
750 doSyncSize(widthCtrl, heightCtrl);
751 };
752 var syncSize = function (win) {
753 doSizeControls(win, doSyncSize);
754 };
755 var updateSize = function (win) {
756 doSizeControls(win, doUpdateSize);
757 };
758 var createUi = function () {
759 var recalcSize = function (evt) {
760 updateSize(evt.control.rootControl);
761 };
762 return {
763 type: 'container',
764 label: 'Dimensions',
765 layout: 'flex',
766 align: 'center',
767 spacing: 5,
768 items: [
769 {
770 name: 'width',
771 type: 'textbox',
772 maxLength: 5,
773 size: 5,
774 onchange: recalcSize,
775 ariaLabel: 'Width'
776 },
777 {
778 type: 'label',
779 text: 'x'
780 },
781 {
782 name: 'height',
783 type: 'textbox',
784 maxLength: 5,
785 size: 5,
786 onchange: recalcSize,
787 ariaLabel: 'Height'
788 },
789 {
790 name: 'constrain',
791 type: 'checkbox',
792 checked: true,
793 text: 'Constrain proportions'
794 }
795 ]
796 };
797 };
798 var SizeManager = {
799 createUi: createUi,
800 syncSize: syncSize,
801 updateSize: updateSize
802 };
803
804 var onSrcChange = function (evt, editor) {
805 var srcURL, prependURL, absoluteURLPattern;
806 var meta = evt.meta || {};
807 var control = evt.control;
808 var rootControl = control.rootControl;
809 var imageListCtrl = rootControl.find('#image-list')[0];
810 if (imageListCtrl) {
811 imageListCtrl.value(editor.convertURL(control.value(), 'src'));
812 }
813 global$2.each(meta, function (value, key) {
814 rootControl.find('#' + key).value(value);
815 });
816 if (!meta.width && !meta.height) {
817 srcURL = editor.convertURL(control.value(), 'src');
818 prependURL = Settings.getPrependUrl(editor);
819 absoluteURLPattern = new RegExp('^(?:[a-z]+:)?//', 'i');
820 if (prependURL && !absoluteURLPattern.test(srcURL) && srcURL.substring(0, prependURL.length) !== prependURL) {
821 srcURL = prependURL + srcURL;
822 }
823 control.value(srcURL);
824 Utils.getImageSize(editor.documentBaseURI.toAbsolute(control.value()), function (data) {
825 if (data.width && data.height && Settings.hasDimensions(editor)) {
826 rootControl.find('#width').value(data.width);
827 rootControl.find('#height').value(data.height);
828 SizeManager.syncSize(rootControl);
829 }
830 });
831 }
832 };
833 var onBeforeCall = function (evt) {
834 evt.meta = evt.control.rootControl.toJSON();
835 };
836 var getGeneralItems = function (editor, imageListCtrl) {
837 var generalFormItems = [
838 {
839 name: 'src',
840 type: 'filepicker',
841 filetype: 'image',
842 label: 'Source',
843 autofocus: true,
844 onchange: function (evt) {
845 onSrcChange(evt, editor);
846 },
847 onbeforecall: onBeforeCall
848 },
849 imageListCtrl
850 ];
851 if (Settings.hasDescription(editor)) {
852 generalFormItems.push({
853 name: 'alt',
854 type: 'textbox',
855 label: 'Image description'
856 });
857 }
858 if (Settings.hasImageTitle(editor)) {
859 generalFormItems.push({
860 name: 'title',
861 type: 'textbox',
862 label: 'Image Title'
863 });
864 }
865 if (Settings.hasDimensions(editor)) {
866 generalFormItems.push(SizeManager.createUi());
867 }
868 if (Settings.getClassList(editor)) {
869 generalFormItems.push({
870 name: 'class',
871 type: 'listbox',
872 label: 'Class',
873 values: Utils.buildListItems(Settings.getClassList(editor), function (item) {
874 if (item.value) {
875 item.textStyle = function () {
876 return editor.formatter.getCssText({
877 inline: 'img',
878 classes: [item.value]
879 });
880 };
881 }
882 })
883 });
884 }
885 if (Settings.hasImageCaption(editor)) {
886 generalFormItems.push({
887 name: 'caption',
888 type: 'checkbox',
889 label: 'Caption'
890 });
891 }
892 return generalFormItems;
893 };
894 var makeTab$1 = function (editor, imageListCtrl) {
895 return {
896 title: 'General',
897 type: 'form',
898 items: getGeneralItems(editor, imageListCtrl)
899 };
900 };
901 var MainTab = {
902 makeTab: makeTab$1,
903 getGeneralItems: getGeneralItems
904 };
905
906 var url = function () {
907 return Global$1.getOrDie('URL');
908 };
909 var createObjectURL = function (blob) {
910 return url().createObjectURL(blob);
911 };
912 var revokeObjectURL = function (u) {
913 url().revokeObjectURL(u);
914 };
915 var URL = {
916 createObjectURL: createObjectURL,
917 revokeObjectURL: revokeObjectURL
918 };
919
920 var global$5 = tinymce.util.Tools.resolve('tinymce.ui.Factory');
921
922 function XMLHttpRequest () {
923 var f = Global$1.getOrDie('XMLHttpRequest');
924 return new f();
925 }
926
927 var noop = function () {
928 };
929 var pathJoin = function (path1, path2) {
930 if (path1) {
931 return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
932 }
933 return path2;
934 };
935 function Uploader (settings) {
936 var defaultHandler = function (blobInfo, success, failure, progress) {
937 var xhr, formData;
938 xhr = XMLHttpRequest();
939 xhr.open('POST', settings.url);
940 xhr.withCredentials = settings.credentials;
941 xhr.upload.onprogress = function (e) {
942 progress(e.loaded / e.total * 100);
943 };
944 xhr.onerror = function () {
945 failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
946 };
947 xhr.onload = function () {
948 var json;
949 if (xhr.status < 200 || xhr.status >= 300) {
950 failure('HTTP Error: ' + xhr.status);
951 return;
952 }
953 json = JSON.parse(xhr.responseText);
954 if (!json || typeof json.location !== 'string') {
955 failure('Invalid JSON: ' + xhr.responseText);
956 return;
957 }
958 success(pathJoin(settings.basePath, json.location));
959 };
960 formData = new domGlobals.FormData();
961 formData.append('file', blobInfo.blob(), blobInfo.filename());
962 xhr.send(formData);
963 };
964 var uploadBlob = function (blobInfo, handler) {
965 return new global$1(function (resolve, reject) {
966 try {
967 handler(blobInfo, resolve, reject, noop);
968 } catch (ex) {
969 reject(ex.message);
970 }
971 });
972 };
973 var isDefaultHandler = function (handler) {
974 return handler === defaultHandler;
975 };
976 var upload = function (blobInfo) {
977 return !settings.url && isDefaultHandler(settings.handler) ? global$1.reject('Upload url missing from the settings.') : uploadBlob(blobInfo, settings.handler);
978 };
979 settings = global$2.extend({
980 credentials: false,
981 handler: defaultHandler
982 }, settings);
983 return { upload: upload };
984 }
985
986 var onFileInput = function (editor) {
987 return function (evt) {
988 var Throbber = global$5.get('Throbber');
989 var rootControl = evt.control.rootControl;
990 var throbber = new Throbber(rootControl.getEl());
991 var file = evt.control.value();
992 var blobUri = URL.createObjectURL(file);
993 var uploader = Uploader({
994 url: Settings.getUploadUrl(editor),
995 basePath: Settings.getUploadBasePath(editor),
996 credentials: Settings.getUploadCredentials(editor),
997 handler: Settings.getUploadHandler(editor)
998 });
999 var finalize = function () {
1000 throbber.hide();
1001 URL.revokeObjectURL(blobUri);
1002 };
1003 throbber.show();
1004 return Utils.blobToDataUri(file).then(function (dataUrl) {
1005 var blobInfo = editor.editorUpload.blobCache.create({
1006 blob: file,
1007 blobUri: blobUri,
1008 name: file.name ? file.name.replace(/\.[^\.]+$/, '') : null,
1009 base64: dataUrl.split(',')[1]
1010 });
1011 return uploader.upload(blobInfo).then(function (url) {
1012 var src = rootControl.find('#src');
1013 src.value(url);
1014 rootControl.find('tabpanel')[0].activateTab(0);
1015 src.fire('change');
1016 finalize();
1017 return url;
1018 });
1019 }).catch(function (err) {
1020 editor.windowManager.alert(err);
1021 finalize();
1022 });
1023 };
1024 };
1025 var acceptExts = '.jpg,.jpeg,.png,.gif';
1026 var makeTab$2 = function (editor) {
1027 return {
1028 title: 'Upload',
1029 type: 'form',
1030 layout: 'flex',
1031 direction: 'column',
1032 align: 'stretch',
1033 padding: '20 20 20 20',
1034 items: [
1035 {
1036 type: 'container',
1037 layout: 'flex',
1038 direction: 'column',
1039 align: 'center',
1040 spacing: 10,
1041 items: [
1042 {
1043 text: 'Browse for an image',
1044 type: 'browsebutton',
1045 accept: acceptExts,
1046 onchange: onFileInput(editor)
1047 },
1048 {
1049 text: 'OR',
1050 type: 'label'
1051 }
1052 ]
1053 },
1054 {
1055 text: 'Drop an image here',
1056 type: 'dropzone',
1057 accept: acceptExts,
1058 height: 100,
1059 onchange: onFileInput(editor)
1060 }
1061 ]
1062 };
1063 };
1064 var UploadTab = { makeTab: makeTab$2 };
1065
1066 function curry(fn) {
1067 var initialArgs = [];
1068 for (var _i = 1; _i < arguments.length; _i++) {
1069 initialArgs[_i - 1] = arguments[_i];
1070 }
1071 return function () {
1072 var restArgs = [];
1073 for (var _i = 0; _i < arguments.length; _i++) {
1074 restArgs[_i] = arguments[_i];
1075 }
1076 var all = initialArgs.concat(restArgs);
1077 return fn.apply(null, all);
1078 };
1079 }
1080
1081 var submitForm = function (editor, evt) {
1082 var win = evt.control.getRoot();
1083 SizeManager.updateSize(win);
1084 editor.undoManager.transact(function () {
1085 var data = merge(readImageDataFromSelection(editor), win.toJSON());
1086 insertOrUpdateImage(editor, data);
1087 });
1088 editor.editorUpload.uploadImagesAuto();
1089 };
1090 function Dialog (editor) {
1091 function showDialog(imageList) {
1092 var data = readImageDataFromSelection(editor);
1093 var win, imageListCtrl;
1094 if (imageList) {
1095 imageListCtrl = {
1096 type: 'listbox',
1097 label: 'Image list',
1098 name: 'image-list',
1099 values: Utils.buildListItems(imageList, function (item) {
1100 item.value = editor.convertURL(item.value || item.url, 'src');
1101 }, [{
1102 text: 'None',
1103 value: ''
1104 }]),
1105 value: data.src && editor.convertURL(data.src, 'src'),
1106 onselect: function (e) {
1107 var altCtrl = win.find('#alt');
1108 if (!altCtrl.value() || e.lastControl && altCtrl.value() === e.lastControl.text()) {
1109 altCtrl.value(e.control.text());
1110 }
1111 win.find('#src').value(e.control.value()).fire('change');
1112 },
1113 onPostRender: function () {
1114 imageListCtrl = this;
1115 }
1116 };
1117 }
1118 if (Settings.hasAdvTab(editor) || Settings.hasUploadUrl(editor) || Settings.hasUploadHandler(editor)) {
1119 var body = [MainTab.makeTab(editor, imageListCtrl)];
1120 if (Settings.hasAdvTab(editor)) {
1121 body.push(AdvTab.makeTab(editor));
1122 }
1123 if (Settings.hasUploadUrl(editor) || Settings.hasUploadHandler(editor)) {
1124 body.push(UploadTab.makeTab(editor));
1125 }
1126 win = editor.windowManager.open({
1127 title: 'Insert/edit image',
1128 data: data,
1129 bodyType: 'tabpanel',
1130 body: body,
1131 onSubmit: curry(submitForm, editor)
1132 });
1133 } else {
1134 win = editor.windowManager.open({
1135 title: 'Insert/edit image',
1136 data: data,
1137 body: MainTab.getGeneralItems(editor, imageListCtrl),
1138 onSubmit: curry(submitForm, editor)
1139 });
1140 }
1141 SizeManager.syncSize(win);
1142 }
1143 function open() {
1144 Utils.createImageList(editor, showDialog);
1145 }
1146 return { open: open };
1147 }
1148
1149 var register = function (editor) {
1150 editor.addCommand('mceImage', Dialog(editor).open);
1151 };
1152 var Commands = { register: register };
1153
1154 var hasImageClass = function (node) {
1155 var className = node.attr('class');
1156 return className && /\bimage\b/.test(className);
1157 };
1158 var toggleContentEditableState = function (state) {
1159 return function (nodes) {
1160 var i = nodes.length, node;
1161 var toggleContentEditable = function (node) {
1162 node.attr('contenteditable', state ? 'true' : null);
1163 };
1164 while (i--) {
1165 node = nodes[i];
1166 if (hasImageClass(node)) {
1167 node.attr('contenteditable', state ? 'false' : null);
1168 global$2.each(node.getAll('figcaption'), toggleContentEditable);
1169 }
1170 }
1171 };
1172 };
1173 var setup = function (editor) {
1174 editor.on('preInit', function () {
1175 editor.parser.addNodeFilter('figure', toggleContentEditableState(true));
1176 editor.serializer.addNodeFilter('figure', toggleContentEditableState(false));
1177 });
1178 };
1179 var FilterContent = { setup: setup };
1180
1181 var register$1 = function (editor) {
1182 editor.addButton('image', {
1183 icon: 'image',
1184 tooltip: 'Insert/edit image',
1185 onclick: Dialog(editor).open,
1186 stateSelector: 'img:not([data-mce-object],[data-mce-placeholder]),figure.image'
1187 });
1188 editor.addMenuItem('image', {
1189 icon: 'image',
1190 text: 'Image',
1191 onclick: Dialog(editor).open,
1192 context: 'insert',
1193 prependToContext: true
1194 });
1195 };
1196 var Buttons = { register: register$1 };
1197
1198 global.add('image', function (editor) {
1199 FilterContent.setup(editor);
1200 Buttons.register(editor);
1201 Commands.register(editor);
1202 });
1203 function Plugin () {
1204 }
1205
1206 return Plugin;
1207
1208}(window));
1209})();
1210