3 var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
5 // Used when there is no 'main' module.
6 // The name is probably (hopefully) unique so minification removes for releases.
7 var register_3795 = function (id) {
9 var fragments = id.split('.');
10 var target = Function('return this;')();
11 for (var i = 0; i < fragments.length - 1; ++i) {
12 if (target[fragments[i]] === undefined)
13 target[fragments[i]] = {};
14 target = target[fragments[i]];
16 target[fragments[fragments.length - 1]] = module;
19 var instantiate = function (id) {
20 var actual = defs[id];
21 var dependencies = actual.deps;
22 var definition = actual.defn;
23 var len = dependencies.length;
24 var instances = new Array(len);
25 for (var i = 0; i < len; ++i)
26 instances[i] = dem(dependencies[i]);
27 var defResult = definition.apply(null, instances);
28 if (defResult === undefined)
29 throw 'module [' + id + '] returned undefined';
30 actual.instance = defResult;
33 var def = function (id, dependencies, definition) {
34 if (typeof id !== 'string')
35 throw 'module id must be a string';
36 else if (dependencies === undefined)
37 throw 'no dependencies for ' + id;
38 else if (definition === undefined)
39 throw 'no definition function for ' + id;
47 var dem = function (id) {
48 var actual = defs[id];
49 if (actual === undefined)
50 throw 'module [' + id + '] was undefined';
51 else if (actual.instance === undefined)
53 return actual.instance;
56 var req = function (ids, callback) {
58 var instances = new Array(len);
59 for (var i = 0; i < len; ++i)
60 instances.push(dem(ids[i]));
61 callback.apply(null, callback);
79 // this helps with minificiation when using a lot of global references
80 var defineGlobal = function (id, ref) {
81 define(id, [], function () { return ref; });
84 ["tinymce/inlite/Theme","global!tinymce.ThemeManager","global!tinymce.util.Delay","tinymce/inlite/ui/Panel","tinymce/inlite/ui/Buttons","tinymce/inlite/core/SkinLoader","tinymce/inlite/core/SelectionMatcher","tinymce/inlite/core/ElementMatcher","tinymce/inlite/core/Matcher","tinymce/inlite/alien/Arr","tinymce/inlite/alien/EditorSettings","tinymce/inlite/core/PredicateId","global!tinymce.util.Tools","global!tinymce.ui.Factory","global!tinymce.DOM","tinymce/inlite/ui/Toolbar","tinymce/inlite/ui/Forms","tinymce/inlite/core/Measure","tinymce/inlite/core/Layout","tinymce/inlite/alien/Type","tinymce/inlite/file/Conversions","tinymce/inlite/file/Picker","tinymce/inlite/core/Actions","global!tinymce.EditorManager","global!tinymce.util.Promise","tinymce/inlite/alien/Uuid","tinymce/inlite/alien/Unlink","tinymce/inlite/core/UrlType","global!tinymce.geom.Rect","tinymce/inlite/core/Convert","tinymce/inlite/alien/Bookmark","global!tinymce.dom.TreeWalker","global!tinymce.dom.RangeUtils"]
86 defineGlobal("global!tinymce.ThemeManager", tinymce.ThemeManager);
87 defineGlobal("global!tinymce.util.Delay", tinymce.util.Delay);
88 defineGlobal("global!tinymce.util.Tools", tinymce.util.Tools);
89 defineGlobal("global!tinymce.ui.Factory", tinymce.ui.Factory);
90 defineGlobal("global!tinymce.DOM", tinymce.DOM);
94 * Released under LGPL License.
95 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
97 * License: http://www.tinymce.com/license
98 * Contributing: http://www.tinymce.com/contributing
101 define('tinymce/inlite/alien/Type', [
103 var isType = function (type) {
104 return function (value) {
105 return typeof value === type;
109 var isArray = function (value) {
110 return Array.isArray(value);
113 var isNull = function (value) {
114 return value === null;
117 var isObject = function (predicate) {
118 return function (value) {
119 return !isNull(value) && !isArray(value) && predicate(value);
124 isString: isType("string"),
125 isNumber: isType("number"),
126 isBoolean: isType("boolean"),
127 isFunction: isType("function"),
128 isObject: isObject(isType("object")),
137 * Released under LGPL License.
138 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
140 * License: http://www.tinymce.com/license
141 * Contributing: http://www.tinymce.com/contributing
144 define('tinymce/inlite/ui/Toolbar', [
145 'global!tinymce.util.Tools',
146 'global!tinymce.ui.Factory',
147 'tinymce/inlite/alien/Type'
148 ], function (Tools, Factory, Type) {
149 var setActiveItem = function (item, name) {
150 return function(state, args) {
151 var nodeName, i = args.parents.length;
154 nodeName = args.parents[i].nodeName;
155 if (nodeName == 'OL' || nodeName == 'UL') {
160 item.active(state && nodeName == name);
164 var getSelectorStateResult = function (itemName, item) {
165 var result = function (selector, handler) {
172 var activeHandler = function(state) {
176 var disabledHandler = function (state) {
177 item.disabled(state);
180 if (itemName == 'bullist') {
181 return result('ul > li', setActiveItem(item, 'UL'));
184 if (itemName == 'numlist') {
185 return result('ol > li', setActiveItem(item, 'OL'));
188 if (item.settings.stateSelector) {
189 return result(item.settings.stateSelector, activeHandler);
192 if (item.settings.disabledStateSelector) {
193 return result(item.settings.disabledStateSelector, disabledHandler);
199 var bindSelectorChanged = function (editor, itemName, item) {
201 var result = getSelectorStateResult(itemName, item);
202 if (result !== null) {
203 editor.selection.selectorChanged(result.selector, result.handler);
208 var itemsToArray = function (items) {
209 if (Type.isArray(items)) {
211 } else if (Type.isString(items)) {
212 return items.split(/[ ,]/);
218 var create = function (editor, name, items) {
219 var toolbarItems = [], buttonGroup;
225 Tools.each(itemsToArray(items), function(item) {
231 if (Factory.has(item)) {
233 toolbarItems.push(item);
236 if (editor.buttons[item]) {
238 buttonGroup = {type: 'buttongroup', items: []};
239 toolbarItems.push(buttonGroup);
243 item = editor.buttons[itemName];
245 if (typeof item == 'function') {
249 item.type = item.type || 'button';
251 item = Factory.create(item);
252 item.on('postRender', bindSelectorChanged(editor, itemName, item));
253 buttonGroup.items.push(item);
259 return Factory.create({
272 defineGlobal("global!tinymce.util.Promise", tinymce.util.Promise);
276 * Released under LGPL License.
277 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
279 * License: http://www.tinymce.com/license
280 * Contributing: http://www.tinymce.com/contributing
284 * Generates unique ids this is the same as in core but since
285 * it's not exposed as a global we can't access it.
287 define("tinymce/inlite/alien/Uuid", [
291 var seed = function () {
292 var rnd = function () {
293 return Math.round(Math.random() * 0xFFFFFFFF).toString(36);
296 return 's' + Date.now().toString(36) + rnd() + rnd() + rnd();
299 var uuid = function (prefix) {
300 return prefix + (count++) + seed();
311 * Released under LGPL License.
312 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
314 * License: http://www.tinymce.com/license
315 * Contributing: http://www.tinymce.com/contributing
318 define('tinymce/inlite/alien/Bookmark', [
321 * Returns a range bookmark. This will convert indexed bookmarks into temporary span elements with
322 * index 0 so that they can be restored properly after the DOM has been modified. Text bookmarks will not have spans
323 * added to them since they can be restored after a dom operation.
325 * So this: <p><b>|</b><b>|</b></p>
326 * becomes: <p><b><span data-mce-type="bookmark">|</span></b><b data-mce-type="bookmark">|</span></b></p>
328 * @param {DOMRange} rng DOM Range to get bookmark on.
329 * @return {Object} Bookmark object.
331 var create = function (dom, rng) {
334 function setupEndPoint(start) {
335 var offsetNode, container, offset;
337 container = rng[start ? 'startContainer' : 'endContainer'];
338 offset = rng[start ? 'startOffset' : 'endOffset'];
340 if (container.nodeType == 1) {
341 offsetNode = dom.create('span', {'data-mce-type': 'bookmark'});
343 if (container.hasChildNodes()) {
344 offset = Math.min(offset, container.childNodes.length - 1);
347 container.insertBefore(offsetNode, container.childNodes[offset]);
349 dom.insertAfter(offsetNode, container.childNodes[offset]);
352 container.appendChild(offsetNode);
355 container = offsetNode;
359 bookmark[start ? 'startContainer' : 'endContainer'] = container;
360 bookmark[start ? 'startOffset' : 'endOffset'] = offset;
365 if (!rng.collapsed) {
373 * Moves the selection to the current bookmark and removes any selection container wrappers.
375 * @param {Object} bookmark Bookmark object to move selection to.
377 var resolve = function (dom, bookmark) {
378 function restoreEndPoint(start) {
379 var container, offset, node;
381 function nodeIndex(container) {
382 var node = container.parentNode.firstChild, idx = 0;
385 if (node == container) {
389 // Skip data-mce-type=bookmark nodes
390 if (node.nodeType != 1 || node.getAttribute('data-mce-type') != 'bookmark') {
394 node = node.nextSibling;
400 container = node = bookmark[start ? 'startContainer' : 'endContainer'];
401 offset = bookmark[start ? 'startOffset' : 'endOffset'];
407 if (container.nodeType == 1) {
408 offset = nodeIndex(container);
409 container = container.parentNode;
413 bookmark[start ? 'startContainer' : 'endContainer'] = container;
414 bookmark[start ? 'startOffset' : 'endOffset'] = offset;
417 restoreEndPoint(true);
420 var rng = dom.createRng();
422 rng.setStart(bookmark.startContainer, bookmark.startOffset);
424 if (bookmark.endContainer) {
425 rng.setEnd(bookmark.endContainer, bookmark.endOffset);
439 defineGlobal("global!tinymce.dom.TreeWalker", tinymce.dom.TreeWalker);
440 defineGlobal("global!tinymce.dom.RangeUtils", tinymce.dom.RangeUtils);
444 * Released under LGPL License.
445 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
447 * License: http://www.tinymce.com/license
448 * Contributing: http://www.tinymce.com/contributing
452 * Unlink implementation that doesn't leave partial links for example it would produce:
453 * a[b<a href="x">c]d</a>e -> a[bc]de
455 * a[b<a href="x">c]d</a>e -> a[bc]<a href="x">d</a>e
457 define("tinymce/inlite/alien/Unlink", [
458 'tinymce/inlite/alien/Bookmark',
459 'global!tinymce.util.Tools',
460 'global!tinymce.dom.TreeWalker',
461 'global!tinymce.dom.RangeUtils'
462 ], function (Bookmark, Tools, TreeWalker, RangeUtils) {
463 var getSelectedElements = function (rootElm, startNode, endNode) {
464 var walker, node, elms = [];
466 walker = new TreeWalker(startNode, rootElm);
467 for (node = startNode; node; node = walker.next()) {
468 if (node.nodeType === 1) {
472 if (node === endNode) {
480 var unwrapElements = function (editor, elms) {
481 var bookmark, dom, selection;
484 selection = editor.selection;
485 bookmark = Bookmark.create(dom, selection.getRng());
487 Tools.each(elms, function (elm) {
488 editor.dom.remove(elm, true);
491 selection.setRng(Bookmark.resolve(dom, bookmark));
494 var isLink = function (elm) {
495 return elm.nodeName === 'A' && elm.hasAttribute('href');
498 var getParentAnchorOrSelf = function (dom, elm) {
499 var anchorElm = dom.getParent(elm, isLink);
500 return anchorElm ? anchorElm : elm;
503 var getSelectedAnchors = function (editor) {
504 var startElm, endElm, rootElm, anchorElms, selection, dom, rng;
506 selection = editor.selection;
508 rng = selection.getRng();
509 startElm = getParentAnchorOrSelf(dom, RangeUtils.getNode(rng.startContainer, rng.startOffset));
510 endElm = RangeUtils.getNode(rng.endContainer, rng.endOffset);
511 rootElm = editor.getBody();
512 anchorElms = Tools.grep(getSelectedElements(rootElm, startElm, endElm), isLink);
517 var unlinkSelection = function (editor) {
518 unwrapElements(editor, getSelectedAnchors(editor));
522 unlinkSelection: unlinkSelection
529 * Released under LGPL License.
530 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
532 * License: http://www.tinymce.com/license
533 * Contributing: http://www.tinymce.com/contributing
536 define('tinymce/inlite/core/Actions', [
537 'tinymce/inlite/alien/Uuid',
538 'tinymce/inlite/alien/Unlink'
539 ], function (Uuid, Unlink) {
540 var createTableHtml = function (cols, rows) {
543 html = '<table data-mce-id="mce" style="width: 100%">';
546 for (y = 0; y < rows; y++) {
549 for (x = 0; x < cols; x++) {
550 html += '<td><br></td>';
562 var getInsertedElement = function (editor) {
563 var elms = editor.dom.select('*[data-mce-id]');
567 var insertTable = function (editor, cols, rows) {
568 editor.undoManager.transact(function () {
569 var tableElm, cellElm;
571 editor.insertContent(createTableHtml(cols, rows));
573 tableElm = getInsertedElement(editor);
574 tableElm.removeAttribute('data-mce-id');
575 cellElm = editor.dom.select('td,th', tableElm);
576 editor.selection.setCursorLocation(cellElm[0], 0);
580 var formatBlock = function (editor, formatName) {
581 editor.execCommand('FormatBlock', false, formatName);
584 var insertBlob = function (editor, base64, blob) {
585 var blobCache, blobInfo;
587 blobCache = editor.editorUpload.blobCache;
588 blobInfo = blobCache.create(Uuid.uuid('mceu'), blob, base64);
589 blobCache.add(blobInfo);
591 editor.insertContent(editor.dom.createHTML('img', {src: blobInfo.blobUri()}));
594 var collapseSelectionToEnd = function (editor) {
595 editor.selection.collapse(false);
598 var unlink = function (editor) {
600 Unlink.unlinkSelection(editor);
601 collapseSelectionToEnd(editor);
604 var changeHref = function (editor, elm, url) {
606 editor.dom.setAttrib(elm, 'href', url);
607 collapseSelectionToEnd(editor);
610 var insertLink = function (editor, url) {
611 editor.execCommand('mceInsertLink', false, {href: url});
612 collapseSelectionToEnd(editor);
615 var updateOrInsertLink = function (editor, url) {
616 var elm = editor.dom.getParent(editor.selection.getStart(), 'a[href]');
617 elm ? changeHref(editor, elm, url) : insertLink(editor, url);
620 var createLink = function (editor, url) {
621 url.trim().length === 0 ? unlink(editor) : updateOrInsertLink(editor, url);
625 insertTable: insertTable,
626 formatBlock: formatBlock,
627 insertBlob: insertBlob,
628 createLink: createLink,
636 * Released under LGPL License.
637 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
639 * License: http://www.tinymce.com/license
640 * Contributing: http://www.tinymce.com/contributing
643 define('tinymce/inlite/core/UrlType', [
645 var isDomainLike = function (href) {
646 return /^www\.|\.(com|org|edu|gov|uk|net|ca|de|jp|fr|au|us|ru|ch|it|nl|se|no|es|mil)$/i.test(href.trim());
649 var isAbsolute = function (href) {
650 return /^https?:\/\//.test(href.trim());
654 isDomainLike: isDomainLike,
655 isAbsolute: isAbsolute
664 * Released under LGPL License.
665 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
667 * License: http://www.tinymce.com/license
668 * Contributing: http://www.tinymce.com/contributing
671 define('tinymce/inlite/ui/Forms', [
672 'global!tinymce.util.Tools',
673 'global!tinymce.ui.Factory',
674 'global!tinymce.util.Promise',
675 'tinymce/inlite/core/Actions',
676 'tinymce/inlite/core/UrlType'
677 ], function (Tools, Factory, Promise, Actions, UrlType) {
678 var focusFirstTextBox = function (form) {
679 form.find('textbox').eq(0).each(function (ctrl) {
684 var createForm = function (name, spec) {
685 var form = Factory.create(
696 form.on('show', function () {
697 focusFirstTextBox(form);
703 var toggleVisibility = function (ctrl, state) {
704 return state ? ctrl.show() : ctrl.hide();
707 var askAboutPrefix = function (editor, href) {
708 return new Promise(function (resolve) {
709 editor.windowManager.confirm(
710 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
712 var output = result === true ? 'http://' + href : href;
719 var convertLinkToAbsolute = function (editor, href) {
720 return !UrlType.isAbsolute(href) && UrlType.isDomainLike(href) ? askAboutPrefix(editor, href) : Promise.resolve(href);
723 var createQuickLinkForm = function (editor, hide) {
724 var unlink = function () {
726 Actions.unlink(editor);
730 return createForm('quicklink', {
732 {type: 'button', name: 'unlink', icon: 'unlink', onclick: unlink, tooltip: 'Remove link'},
733 {type: 'textbox', name: 'linkurl', placeholder: 'Paste or type a link'},
734 {type: 'button', icon: 'checkmark', subtype: 'primary', tooltip: 'Ok', onclick: 'submit'}
736 onshow: function () {
737 var elm, linkurl = '';
739 elm = editor.dom.getParent(editor.selection.getStart(), 'a[href]');
741 linkurl = editor.dom.getAttrib(elm, 'href');
748 toggleVisibility(this.find('#unlink'), elm);
750 onsubmit: function (e) {
751 convertLinkToAbsolute(editor, e.data.linkurl).then(function (url) {
752 Actions.createLink(editor, url);
760 createQuickLinkForm: createQuickLinkForm
764 defineGlobal("global!tinymce.geom.Rect", tinymce.geom.Rect);
768 * Released under LGPL License.
769 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
771 * License: http://www.tinymce.com/license
772 * Contributing: http://www.tinymce.com/contributing
775 define('tinymce/inlite/core/Convert', [
777 var fromClientRect = function (clientRect) {
786 var toClientRect = function (geomRect) {
792 right: geomRect.x + geomRect.w,
793 bottom: geomRect.y + geomRect.h
798 fromClientRect: fromClientRect,
799 toClientRect: toClientRect
806 * Released under LGPL License.
807 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
809 * License: http://www.tinymce.com/license
810 * Contributing: http://www.tinymce.com/contributing
813 define('tinymce/inlite/core/Measure', [
814 'global!tinymce.DOM',
815 'global!tinymce.geom.Rect',
816 'tinymce/inlite/core/Convert'
817 ], function (DOM, Rect, Convert) {
818 var toAbsolute = function (rect) {
819 var vp = DOM.getViewPort();
829 var measureElement = function (elm) {
830 var clientRect = elm.getBoundingClientRect();
835 w: Math.max(elm.clientWidth, elm.offsetWidth),
836 h: Math.max(elm.clientHeight, elm.offsetHeight)
840 var getElementRect = function (editor, elm) {
841 return measureElement(elm);
844 var getPageAreaRect = function (editor) {
845 return measureElement(editor.getElement().ownerDocument.body);
848 var getContentAreaRect = function (editor) {
849 return measureElement(editor.getContentAreaContainer() || editor.getBody());
852 var getSelectionRect = function (editor) {
853 var clientRect = editor.selection.getBoundingClientRect();
854 return clientRect ? toAbsolute(Convert.fromClientRect(clientRect)) : null;
858 getElementRect: getElementRect,
859 getPageAreaRect: getPageAreaRect,
860 getContentAreaRect: getContentAreaRect,
861 getSelectionRect: getSelectionRect
868 * Released under LGPL License.
869 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
871 * License: http://www.tinymce.com/license
872 * Contributing: http://www.tinymce.com/contributing
875 define('tinymce/inlite/core/Layout', [
876 'global!tinymce.geom.Rect',
877 'tinymce/inlite/core/Convert'
878 ], function (Rect, Convert) {
879 var result = function (rect, position) {
886 var moveTo = function (rect, toRect) {
887 return {x: toRect.x, y: toRect.y, w: rect.w, h: rect.h};
890 var calcByPositions = function (testPositions1, testPositions2, targetRect, contentAreaRect, panelRect) {
891 var relPos, relRect, outputPanelRect;
893 relPos = Rect.findBestRelativePosition(panelRect, targetRect, contentAreaRect, testPositions1);
894 targetRect = Rect.clamp(targetRect, contentAreaRect);
897 relRect = Rect.relativePosition(panelRect, targetRect, relPos);
898 outputPanelRect = moveTo(panelRect, relRect);
899 return result(outputPanelRect, relPos);
902 targetRect = Rect.intersect(contentAreaRect, targetRect);
904 relPos = Rect.findBestRelativePosition(panelRect, targetRect, contentAreaRect, testPositions2);
906 relRect = Rect.relativePosition(panelRect, targetRect, relPos);
907 outputPanelRect = moveTo(panelRect, relRect);
908 return result(outputPanelRect, relPos);
911 outputPanelRect = moveTo(panelRect, targetRect);
912 return result(outputPanelRect, relPos);
918 var calcInsert = function (targetRect, contentAreaRect, panelRect) {
919 return calcByPositions(
921 ['bc-tc', 'bl-tl', 'br-tr'],
928 var calc = function (targetRect, contentAreaRect, panelRect) {
929 return calcByPositions(
930 ['tc-bc', 'bc-tc', 'tl-bl', 'bl-tl', 'tr-br', 'br-tr'],
931 ['bc-tc', 'bl-tl', 'br-tr'],
938 var userConstrain = function (handler, targetRect, contentAreaRect, panelRect) {
939 var userConstrainedPanelRect;
941 if (typeof handler === 'function') {
942 userConstrainedPanelRect = handler({
943 elementRect: Convert.toClientRect(targetRect),
944 contentAreaRect: Convert.toClientRect(contentAreaRect),
945 panelRect: Convert.toClientRect(panelRect)
948 return Convert.fromClientRect(userConstrainedPanelRect);
954 var defaultHandler = function (rects) {
955 return rects.panelRect;
959 calcInsert: calcInsert,
961 userConstrain: userConstrain,
962 defaultHandler: defaultHandler
969 * Released under LGPL License.
970 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
972 * License: http://www.tinymce.com/license
973 * Contributing: http://www.tinymce.com/contributing
976 define('tinymce/inlite/alien/EditorSettings', [
977 'tinymce/inlite/alien/Type'
979 var validDefaultOrDie = function (value, predicate) {
980 if (predicate(value)) {
984 throw new Error('Default value doesn\'t match requested type.');
987 var getByTypeOr = function (predicate) {
988 return function (editor, name, defaultValue) {
989 var settings = editor.settings;
990 validDefaultOrDie(defaultValue, predicate);
991 return name in settings && predicate(settings[name]) ? settings[name] : defaultValue;
995 var splitNoEmpty = function (str, delim) {
996 return str.split(delim).filter(function (item) {
997 return item.length > 0;
1001 var itemsToArray = function (value, defaultValue) {
1002 var stringToItemsArray = function (value) {
1003 return typeof value === 'string' ? splitNoEmpty(value, /[ ,]/) : value;
1006 var boolToItemsArray = function (value, defaultValue) {
1007 return value === false ? [ ] : defaultValue;
1010 if (Type.isArray(value)) {
1012 } else if (Type.isString(value)) {
1013 return stringToItemsArray(value);
1014 } else if (Type.isBoolean(value)) {
1015 return boolToItemsArray(value, defaultValue);
1018 return defaultValue;
1021 var getToolbarItemsOr = function (predicate) {
1022 return function (editor, name, defaultValue) {
1023 var value = name in editor.settings ? editor.settings[name] : defaultValue;
1024 validDefaultOrDie(defaultValue, predicate);
1025 return itemsToArray(value, defaultValue);
1030 // TODO: Add Option based getString, getBool if merged with core
1031 getStringOr: getByTypeOr(Type.isString),
1032 getBoolOr: getByTypeOr(Type.isBoolean),
1033 getNumberOr: getByTypeOr(Type.isNumber),
1034 getHandlerOr: getByTypeOr(Type.isFunction),
1035 getToolbarItemsOr: getToolbarItemsOr(Type.isArray)
1042 * Released under LGPL License.
1043 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1045 * License: http://www.tinymce.com/license
1046 * Contributing: http://www.tinymce.com/contributing
1049 define('tinymce/inlite/ui/Panel', [
1050 'global!tinymce.util.Tools',
1051 'global!tinymce.ui.Factory',
1052 'global!tinymce.DOM',
1053 'tinymce/inlite/ui/Toolbar',
1054 'tinymce/inlite/ui/Forms',
1055 'tinymce/inlite/core/Measure',
1056 'tinymce/inlite/core/Layout',
1057 'tinymce/inlite/alien/EditorSettings'
1058 ], function (Tools, Factory, DOM, Toolbar, Forms, Measure, Layout, EditorSettings) {
1059 return function () {
1060 var DEFAULT_TEXT_SELECTION_ITEMS = ['bold', 'italic', '|', 'quicklink', 'h2', 'h3', 'blockquote'];
1061 var DEFAULT_INSERT_TOOLBAR_ITEMS = ['quickimage', 'quicktable'];
1062 var panel, currentRect;
1064 var createToolbars = function (editor, toolbars) {
1065 return Tools.map(toolbars, function (toolbar) {
1066 return Toolbar.create(editor, toolbar.id, toolbar.items);
1070 var getTextSelectionToolbarItems = function (editor) {
1071 return EditorSettings.getToolbarItemsOr(editor, 'selection_toolbar', DEFAULT_TEXT_SELECTION_ITEMS);
1074 var getInsertToolbarItems = function (editor) {
1075 return EditorSettings.getToolbarItemsOr(editor, 'insert_toolbar', DEFAULT_INSERT_TOOLBAR_ITEMS);
1078 var hasToolbarItems = function (toolbar) {
1079 return toolbar.items().length > 0;
1082 var create = function (editor, toolbars) {
1083 var items = createToolbars(editor, toolbars).concat([
1084 Toolbar.create(editor, 'text', getTextSelectionToolbarItems(editor)),
1085 Toolbar.create(editor, 'insert', getInsertToolbarItems(editor)),
1086 Forms.createQuickLinkForm(editor, hide)
1089 return Factory.create({
1092 classes: 'tinymce tinymce-inline arrow',
1093 ariaLabel: 'Inline toolbar',
1095 direction: 'column',
1101 items: Tools.grep(items, hasToolbarItems),
1102 oncancel: function() {
1108 var showPanel = function (panel) {
1114 var movePanelTo = function (panel, pos) {
1115 panel.moveTo(pos.x, pos.y);
1118 var togglePositionClass = function (panel, relPos) {
1119 relPos = relPos ? relPos.substr(0, 2) : '';
1125 }, function(cls, pos) {
1126 panel.classes.toggle('arrow-' + cls, pos === relPos.substr(0, 1));
1129 if (relPos === 'cr') {
1130 panel.classes.toggle('arrow-left', true);
1131 panel.classes.toggle('arrow-right', false);
1132 } else if (relPos === 'cl') {
1133 panel.classes.toggle('arrow-left', true);
1134 panel.classes.toggle('arrow-right', true);
1139 }, function(cls, pos) {
1140 panel.classes.toggle('arrow-' + cls, pos === relPos.substr(1, 1));
1145 var showToolbar = function (panel, id) {
1146 var toolbars = panel.items().filter('#' + id);
1148 if (toolbars.length > 0) {
1157 var showPanelAt = function (panel, id, editor, targetRect) {
1158 var contentAreaRect, panelRect, result, userConstainHandler;
1161 panel.items().hide();
1163 if (!showToolbar(panel, id)) {
1168 userConstainHandler = EditorSettings.getHandlerOr(editor, 'inline_toolbar_position_handler', Layout.defaultHandler);
1169 contentAreaRect = Measure.getContentAreaRect(editor);
1170 panelRect = DOM.getRect(panel.getEl());
1172 if (id === 'insert') {
1173 result = Layout.calcInsert(targetRect, contentAreaRect, panelRect);
1175 result = Layout.calc(targetRect, contentAreaRect, panelRect);
1179 panelRect = result.rect;
1180 currentRect = targetRect;
1181 movePanelTo(panel, Layout.userConstrain(userConstainHandler, targetRect, contentAreaRect, panelRect));
1182 togglePositionClass(panel, result.position);
1188 var hasFormVisible = function () {
1189 return panel.items().filter('form:visible').length > 0;
1192 var showForm = function (editor, id) {
1194 panel.items().hide();
1196 if (!showToolbar(panel, id)) {
1201 var contentAreaRect, panelRect, result, userConstainHandler;
1204 panel.items().hide();
1205 showToolbar(panel, id);
1207 userConstainHandler = EditorSettings.getHandlerOr(editor, 'inline_toolbar_position_handler', Layout.defaultHandler);
1208 contentAreaRect = Measure.getContentAreaRect(editor);
1209 panelRect = DOM.getRect(panel.getEl());
1211 result = Layout.calc(currentRect, contentAreaRect, panelRect);
1214 panelRect = result.rect;
1215 movePanelTo(panel, Layout.userConstrain(userConstainHandler, currentRect, contentAreaRect, panelRect));
1216 togglePositionClass(panel, result.position);
1221 var show = function (editor, id, targetRect, toolbars) {
1223 panel = create(editor, toolbars);
1224 panel.renderTo(document.body).reflow().moveTo(targetRect.x, targetRect.y);
1225 editor.nodeChanged();
1228 showPanelAt(panel, id, editor, targetRect);
1231 var hide = function () {
1237 var focus = function () {
1239 panel.find('toolbar:visible').eq(0).each(function (item) {
1245 var remove = function () {
1252 var inForm = function () {
1253 return panel && panel.visible() && hasFormVisible();
1270 * Released under LGPL License.
1271 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1273 * License: http://www.tinymce.com/license
1274 * Contributing: http://www.tinymce.com/contributing
1277 define('tinymce/inlite/file/Conversions', [
1278 'global!tinymce.util.Promise'
1279 ], function (Promise) {
1280 var blobToBase64 = function (blob) {
1281 return new Promise(function(resolve) {
1282 var reader = new FileReader();
1284 reader.onloadend = function() {
1285 resolve(reader.result.split(',')[1]);
1288 reader.readAsDataURL(blob);
1293 blobToBase64: blobToBase64
1302 * Released under LGPL License.
1303 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1305 * License: http://www.tinymce.com/license
1306 * Contributing: http://www.tinymce.com/contributing
1309 define('tinymce/inlite/file/Picker', [
1310 'global!tinymce.util.Promise'
1311 ], function (Promise) {
1312 var pickFile = function () {
1313 return new Promise(function (resolve) {
1316 fileInput = document.createElement("input");
1317 fileInput.type = "file";
1318 fileInput.style.position = 'fixed';
1319 fileInput.style.left = 0;
1320 fileInput.style.top = 0;
1321 fileInput.style.opacity = 0.001;
1322 document.body.appendChild(fileInput);
1324 fileInput.onchange = function(e) {
1325 resolve(Array.prototype.slice.call(e.target.files));
1329 fileInput.parentNode.removeChild(fileInput);
1343 * Released under LGPL License.
1344 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1346 * License: http://www.tinymce.com/license
1347 * Contributing: http://www.tinymce.com/contributing
1350 define('tinymce/inlite/ui/Buttons', [
1351 'tinymce/inlite/ui/Panel',
1352 'tinymce/inlite/file/Conversions',
1353 'tinymce/inlite/file/Picker',
1354 'tinymce/inlite/core/Actions'
1355 ], function (Panel, Conversions, Picker, Actions) {
1356 var addHeaderButtons = function (editor) {
1357 var formatBlock = function (name) {
1358 return function () {
1359 Actions.formatBlock(editor, name);
1363 for (var i = 1; i < 6; i++) {
1366 editor.addButton(name, {
1367 text: name.toUpperCase(),
1368 tooltip: 'Heading ' + i,
1369 stateSelector: name,
1370 onclick: formatBlock(name),
1371 onPostRender: function () {
1372 // TODO: Remove this hack that produces bold H1-H6 when we have proper icons
1373 var span = this.getEl().firstChild.firstChild;
1374 span.style.fontWeight = 'bold';
1380 var addToEditor = function (editor, panel) {
1381 editor.addButton('quicklink', {
1383 tooltip: 'Insert/Edit link',
1384 stateSelector: 'a[href]',
1385 onclick: function () {
1386 panel.showForm(editor, 'quicklink');
1390 editor.addButton('quickimage', {
1392 tooltip: 'Insert image',
1393 onclick: function () {
1394 Picker.pickFile().then(function (files) {
1395 var blob = files[0];
1397 Conversions.blobToBase64(blob).then(function (base64) {
1398 Actions.insertBlob(editor, base64, blob);
1404 editor.addButton('quicktable', {
1406 tooltip: 'Insert table',
1407 onclick: function () {
1409 Actions.insertTable(editor, 2, 2);
1413 addHeaderButtons(editor);
1417 addToEditor: addToEditor
1421 defineGlobal("global!tinymce.EditorManager", tinymce.EditorManager);
1425 * Released under LGPL License.
1426 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1428 * License: http://www.tinymce.com/license
1429 * Contributing: http://www.tinymce.com/contributing
1432 define('tinymce/inlite/core/SkinLoader', [
1433 'global!tinymce.EditorManager',
1434 'global!tinymce.DOM'
1435 ], function (EditorManager, DOM) {
1436 var fireSkinLoaded = function (editor, callback) {
1437 var done = function () {
1438 editor.fire('SkinLoaded');
1442 if (editor.initialized) {
1445 editor.on('init', done);
1449 var urlFromName = function (name) {
1450 var prefix = EditorManager.baseURL + '/skins/';
1451 return name ? prefix + name : prefix + 'lightgray';
1454 var toAbsoluteUrl = function (editor, url) {
1455 return editor.documentBaseURI.toAbsolute(url);
1458 var load = function (editor, callback) {
1459 var settings = editor.settings;
1460 var skinUrl = settings.skin_url ? toAbsoluteUrl(editor, settings.skin_url) : urlFromName(settings.skin);
1462 var done = function () {
1463 fireSkinLoaded(editor, callback);
1466 DOM.styleSheetLoader.load(skinUrl + '/skin.min.css', done);
1467 editor.contentCSS.push(skinUrl + '/content.inline.min.css');
1480 * Released under LGPL License.
1481 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1483 * License: http://www.tinymce.com/license
1484 * Contributing: http://www.tinymce.com/contributing
1487 define('tinymce/inlite/core/Matcher', [
1489 // result :: String, Rect -> Matcher.result
1490 var result = function (id, rect) {
1497 // match :: Editor, [(Editor -> Matcher.result | Null)] -> Matcher.result | Null
1498 var match = function (editor, matchers) {
1499 for (var i = 0; i < matchers.length; i++) {
1500 var f = matchers[i];
1501 var result = f(editor);
1518 * SelectionMatcher.js
1520 * Released under LGPL License.
1521 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1523 * License: http://www.tinymce.com/license
1524 * Contributing: http://www.tinymce.com/contributing
1527 define('tinymce/inlite/core/SelectionMatcher', [
1528 'tinymce/inlite/core/Matcher',
1529 'tinymce/inlite/core/Measure'
1530 ], function (Matcher, Measure) {
1531 // textSelection :: String -> (Editor -> Matcher.result | Null)
1532 var textSelection = function (id) {
1533 return function (editor) {
1534 if (!editor.selection.isCollapsed()) {
1535 return Matcher.result(id, Measure.getSelectionRect(editor));
1542 // emptyTextBlock :: [Elements], String -> (Editor -> Matcher.result | Null)
1543 var emptyTextBlock = function (elements, id) {
1544 return function (editor) {
1545 var i, textBlockElementsMap = editor.schema.getTextBlockElements();
1547 for (i = 0; i < elements.length; i++) {
1548 if (elements[i].nodeName === 'TABLE') {
1553 for (i = 0; i < elements.length; i++) {
1554 if (elements[i].nodeName in textBlockElementsMap) {
1555 if (editor.dom.isEmpty(elements[i])) {
1556 return Matcher.result(id, Measure.getSelectionRect(editor));
1568 textSelection: textSelection,
1569 emptyTextBlock: emptyTextBlock
1576 * Released under LGPL License.
1577 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1579 * License: http://www.tinymce.com/license
1580 * Contributing: http://www.tinymce.com/contributing
1583 define('tinymce/inlite/core/ElementMatcher', [
1584 'tinymce/inlite/core/Matcher',
1585 'tinymce/inlite/core/Measure'
1586 ], function (Matcher, Measure) {
1587 // element :: Element, [PredicateId] -> (Editor -> Matcher.result | Null)
1588 var element = function (element, predicateIds) {
1589 return function (editor) {
1590 for (var i = 0; i < predicateIds.length; i++) {
1591 if (predicateIds[i].predicate(element)) {
1592 return Matcher.result(predicateIds[i].id, Measure.getElementRect(editor, element));
1600 // parent :: [Elements], [PredicateId] -> (Editor -> Matcher.result | Null)
1601 var parent = function (elements, predicateIds) {
1602 return function (editor) {
1603 for (var i = 0; i < elements.length; i++) {
1604 for (var x = 0; x < predicateIds.length; x++) {
1605 if (predicateIds[x].predicate(elements[i])) {
1606 return Matcher.result(predicateIds[x].id, Measure.getElementRect(editor, elements[i]));
1624 * Released under LGPL License.
1625 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1627 * License: http://www.tinymce.com/license
1628 * Contributing: http://www.tinymce.com/contributing
1631 define('tinymce/inlite/alien/Arr', [
1633 var flatten = function (arr) {
1634 return arr.reduce(function (results, item) {
1635 return Array.isArray(item) ? results.concat(flatten(item)) : results.concat(item);
1647 * Released under LGPL License.
1648 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1650 * License: http://www.tinymce.com/license
1651 * Contributing: http://www.tinymce.com/contributing
1654 define('tinymce/inlite/core/PredicateId', [
1655 'global!tinymce.util.Tools'
1656 ], function (Tools) {
1657 var create = function (id, predicate) {
1660 predicate: predicate
1664 // fromContextToolbars :: [ContextToolbar] -> [PredicateId]
1665 var fromContextToolbars = function (toolbars) {
1666 return Tools.map(toolbars, function (toolbar) {
1667 return create(toolbar.id, toolbar.predicate);
1673 fromContextToolbars: fromContextToolbars
1680 * Released under LGPL License.
1681 * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1683 * License: http://www.tinymce.com/license
1684 * Contributing: http://www.tinymce.com/contributing
1687 define('tinymce/inlite/Theme', [
1688 'global!tinymce.ThemeManager',
1689 'global!tinymce.util.Delay',
1690 'tinymce/inlite/ui/Panel',
1691 'tinymce/inlite/ui/Buttons',
1692 'tinymce/inlite/core/SkinLoader',
1693 'tinymce/inlite/core/SelectionMatcher',
1694 'tinymce/inlite/core/ElementMatcher',
1695 'tinymce/inlite/core/Matcher',
1696 'tinymce/inlite/alien/Arr',
1697 'tinymce/inlite/alien/EditorSettings',
1698 'tinymce/inlite/core/PredicateId'
1699 ], function(ThemeManager, Delay, Panel, Buttons, SkinLoader, SelectionMatcher, ElementMatcher, Matcher, Arr, EditorSettings, PredicateId) {
1700 var getSelectionElements = function (editor) {
1701 var node = editor.selection.getNode();
1702 var elms = editor.dom.getParents(node);
1706 var createToolbar = function (editor, selector, id, items) {
1707 var selectorPredicate = function (elm) {
1708 return editor.dom.is(elm, selector);
1712 predicate: selectorPredicate,
1718 var getToolbars = function (editor) {
1719 var contextToolbars = editor.contextToolbars;
1721 return Arr.flatten([
1722 contextToolbars ? contextToolbars : [],
1723 createToolbar(editor, 'img', 'image', 'alignleft aligncenter alignright')
1727 var findMatchResult = function (editor, toolbars) {
1728 var result, elements, contextToolbarsPredicateIds;
1730 elements = getSelectionElements(editor);
1731 contextToolbarsPredicateIds = PredicateId.fromContextToolbars(toolbars);
1733 result = Matcher.match(editor, [
1734 ElementMatcher.element(elements[0], contextToolbarsPredicateIds),
1735 SelectionMatcher.textSelection('text'),
1736 SelectionMatcher.emptyTextBlock(elements, 'insert'),
1737 ElementMatcher.parent(elements, contextToolbarsPredicateIds)
1740 return result && result.rect ? result : null;
1743 var togglePanel = function (editor, panel) {
1744 var toggle = function () {
1745 var toolbars = getToolbars(editor);
1746 var result = findMatchResult(editor, toolbars);
1749 panel.show(editor, result.id, result.rect, toolbars);
1755 return function () {
1756 if (!editor.removed) {
1762 var ignoreWhenFormIsVisible = function (panel, f) {
1763 return function () {
1764 if (!panel.inForm()) {
1770 var bindContextualToolbarsEvents = function (editor, panel) {
1771 var throttledTogglePanel = Delay.throttle(togglePanel(editor, panel), 0);
1772 var throttledTogglePanelWhenNotInForm = Delay.throttle(ignoreWhenFormIsVisible(panel, togglePanel(editor, panel)), 0);
1774 editor.on('blur hide ObjectResizeStart', panel.hide);
1775 editor.on('click', throttledTogglePanel);
1776 editor.on('nodeChange mouseup', throttledTogglePanelWhenNotInForm);
1777 editor.on('ResizeEditor ResizeWindow keyup', throttledTogglePanel);
1778 editor.on('remove', panel.remove);
1780 editor.shortcuts.add('Alt+F10', '', panel.focus);
1783 var overrideLinkShortcut = function (editor, panel) {
1784 editor.shortcuts.remove('meta+k');
1785 editor.shortcuts.add('meta+k', '', function () {
1786 var toolbars = getToolbars(editor);
1787 var result = result = Matcher.match(editor, [
1788 SelectionMatcher.textSelection('quicklink')
1792 panel.show(editor, result.id, result.rect, toolbars);
1797 var renderInlineUI = function (editor, panel) {
1798 SkinLoader.load(editor, function () {
1799 bindContextualToolbarsEvents(editor, panel);
1800 overrideLinkShortcut(editor, panel);
1806 var fail = function (message) {
1807 throw new Error(message);
1810 ThemeManager.add('inlite', function (editor) {
1811 var panel = new Panel();
1813 Buttons.addToEditor(editor, panel);
1815 var renderUI = function () {
1816 return editor.inline ? renderInlineUI(editor, panel) : fail('inlite theme only supports inline mode.');
1824 return function() {};
1827 dem('tinymce/inlite/Theme')();