/.*?opera\/([0-9]+)\.([0-9]+).*/
search: checkContains('opera')
versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
search: checkContains('firefox')
/.*?cpu os ([0-9]+)_([0-9]+).*/
search: function (uastring) {
return (contains(uastring, 'safari') || contains(uastring, 'mobile/')) && contains(uastring, 'applewebkit');
search: checkContains('win'),
versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
search: function (uastring) {
return contains(uastring, 'iphone') || contains(uastring, 'ipad');
/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
/.*cpu os ([0-9]+)_([0-9]+).*/,
/.*cpu iphone os ([0-9]+)_([0-9]+).*/
search: checkContains('android'),
versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
search: checkContains('os x'),
versionRegexes: [/.*?os\ x\ ?([0-9]+)_([0-9]+).*/]
search: checkContains('linux'),
search: checkContains('sunos'),
search: checkContains('freebsd'),
browsers: constant(browsers),
var detect$2 = function (userAgent) {
var browsers = PlatformInfo.browsers();
var oses = PlatformInfo.oses();
var browser = UaString.detectBrowser(browsers, userAgent).fold(Browser.unknown, Browser.nu);
var os = UaString.detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
var deviceType = DeviceType(os, browser, userAgent);
var PlatformDetection = { detect: detect$2 };
var detect$3 = cached(function () {
var userAgent = domGlobals.navigator.userAgent;
return PlatformDetection.detect(userAgent);
var PlatformDetection$1 = { detect: detect$3 };
var DOCUMENT$1 = DOCUMENT;
var bypassSelector = function (dom) {
return dom.nodeType !== ELEMENT$1 && dom.nodeType !== DOCUMENT$1 || dom.childElementCount === 0;
var all = function (selector, scope) {
var base = scope === undefined ? domGlobals.document : scope.dom();
return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), Element.fromDom);
var one = function (selector, scope) {
var base = scope === undefined ? domGlobals.document : scope.dom();
return bypassSelector(base) ? Option.none() : Option.from(base.querySelector(selector)).map(Element.fromDom);
var regularContains = function (e1, e2) {
return d1 === d2 ? false : d1.contains(d2);
var ieContains = function (e1, e2) {
return Node.documentPositionContainedBy(e1.dom(), e2.dom());
var browser = PlatformDetection$1.detect().browser;
var contains$1 = browser.isIE() ? ieContains : regularContains;
var spot = Immutable('element', 'offset');
var descendants = function (scope, selector) {
return all(selector, scope);
var trim = global$4.trim;
var hasContentEditableState = function (value) {
if (node && node.nodeType === 1) {
if (node.contentEditable === value) {
if (node.getAttribute('data-mce-contenteditable') === value) {
var isContentEditableTrue = hasContentEditableState('true');
var isContentEditableFalse = hasContentEditableState('false');
var create$4 = function (type, title, url, level, attach) {
var isChildOfContentEditableTrue = function (node) {
while (node = node.parentNode) {
var value = node.contentEditable;
if (value && value !== 'inherit') {
return isContentEditableTrue(node);
var select = function (selector, root) {
return map(descendants(Element.fromDom(root), selector), function (element) {
var getElementText = function (elm) {
return elm.innerText || elm.textContent;
var getOrGenerateId = function (elm) {
return elm.id ? elm.id : generate('h');
var isAnchor = function (elm) {
return elm && elm.nodeName === 'A' && (elm.id || elm.name);
var isValidAnchor = function (elm) {
return isAnchor(elm) && isEditable(elm);
var isHeader = function (elm) {
return elm && /^(H[1-6])$/.test(elm.nodeName);
var isEditable = function (elm) {
return isChildOfContentEditableTrue(elm) && !isContentEditableFalse(elm);
var isValidHeader = function (elm) {
return isHeader(elm) && isEditable(elm);
var getLevel = function (elm) {
return isHeader(elm) ? parseInt(elm.nodeName.substr(1), 10) : 0;
var headerTarget = function (elm) {
var headerId = getOrGenerateId(elm);
var attach = function () {
return create$4('header', getElementText(elm), '#' + headerId, getLevel(elm), attach);
var anchorTarget = function (elm) {
var anchorId = elm.id || elm.name;
var anchorText = getElementText(elm);
return create$4('anchor', anchorText ? anchorText : '#' + anchorId, '#' + anchorId, 0, noop);
var getHeaderTargets = function (elms) {
return map(filter(elms, isValidHeader), headerTarget);
var getAnchorTargets = function (elms) {
return map(filter(elms, isValidAnchor), anchorTarget);
var getTargetElements = function (elm) {
var elms = select('h1,h2,h3,h4,h5,h6,a:not([href])', elm);
var hasTitle = function (target) {
return trim(target.title).length > 0;
var find$2 = function (elm) {
var elms = getTargetElements(elm);
return filter(getHeaderTargets(elms).concat(getAnchorTargets(elms)), hasTitle);
var LinkTargets = { find: find$2 };
var getActiveEditor = function () {
return window.tinymce ? window.tinymce.activeEditor : global$5.activeEditor;
var clearHistory = function () {
var toMenuItem = function (target) {
title: { raw: target.title },
var toMenuItems = function (targets) {
return global$4.map(targets, toMenuItem);
var staticMenuItem = function (title, url) {
var isUniqueUrl = function (url, targets) {
var foundTarget = exists(targets, function (target) {
return target.url === url;
var getSetting = function (editorSettings, name, defaultValue) {
var value = name in editorSettings ? editorSettings[name] : defaultValue;
return value === false ? null : value;
var createMenuItems = function (term, targets, fileType, editorSettings) {
var separator = { title: '-' };
var fromHistoryMenuItems = function (history) {
var historyItems = history.hasOwnProperty(fileType) ? history[fileType] : [];
var uniqueHistory = filter(historyItems, function (url) {
return isUniqueUrl(url, targets);
return global$4.map(uniqueHistory, function (url) {
var fromMenuItems = function (type) {
var filteredTargets = filter(targets, function (target) {
return target.type === type;
return toMenuItems(filteredTargets);
var anchorMenuItems = function () {
var anchorMenuItems = fromMenuItems('anchor');
var topAnchor = getSetting(editorSettings, 'anchor_top', '#top');
var bottomAchor = getSetting(editorSettings, 'anchor_bottom', '#bottom');
if (topAnchor !== null) {
anchorMenuItems.unshift(staticMenuItem('<top>', topAnchor));
if (bottomAchor !== null) {
anchorMenuItems.push(staticMenuItem('<bottom>', bottomAchor));
var join = function (items) {
return foldl(items, function (a, b) {
var bothEmpty = a.length === 0 || b.length === 0;
return bothEmpty ? a.concat(b) : a.concat(separator, b);
if (editorSettings.typeahead_urls === false) {
return fileType === 'file' ? join([
filterByQuery(term, fromHistoryMenuItems(history)),
filterByQuery(term, fromMenuItems('header')),
filterByQuery(term, anchorMenuItems())
]) : filterByQuery(term, fromHistoryMenuItems(history));
var addToHistory = function (url, fileType) {
var items = history[fileType];
if (!/^https?/.test(url)) {
if (indexOf(items, url).isNone()) {
history[fileType] = items.slice(0, HISTORY_LENGTH).concat(url);
history[fileType] = [url];
var filterByQuery = function (term, menuItems) {
var lowerCaseTerm = term.toLowerCase();
var result = global$4.grep(menuItems, function (item) {
return item.title.toLowerCase().indexOf(lowerCaseTerm) !== -1;
return result.length === 1 && result[0].title === term ? [] : result;
var getTitle = function (linkDetails) {
var title = linkDetails.title;
return title.raw ? title.raw : title;
var setupAutoCompleteHandler = function (ctrl, editorSettings, bodyElm, fileType) {
var autocomplete = function (term) {
var linkTargets = LinkTargets.find(bodyElm);
var menuItems = createMenuItems(term, linkTargets, fileType, editorSettings);
ctrl.showAutoComplete(menuItems, term);
ctrl.on('autocomplete', function () {
autocomplete(ctrl.value());
ctrl.on('selectitem', function (e) {
var linkDetails = e.value;
ctrl.value(linkDetails.url);
var title = getTitle(linkDetails);
if (fileType === 'image') {
attach: linkDetails.attach
attach: linkDetails.attach
ctrl.on('click', function (e) {
if (ctrl.value().length === 0 && e.target.nodeName === 'INPUT') {
ctrl.on('PostRender', function () {
ctrl.getRoot().on('submit', function (e) {
if (!e.isDefaultPrevented()) {
addToHistory(ctrl.value(), fileType);
var statusToUiState = function (result) {
var status = result.status, message = result.message;
if (status === 'valid') {
} else if (status === 'unknown') {
} else if (status === 'invalid') {
var setupLinkValidatorHandler = function (ctrl, editorSettings, fileType) {
var validatorHandler = editorSettings.filepicker_validator_handler;
var validateUrl_1 = function (url) {
ctrl.statusLevel('none');
var uiState = statusToUiState(result);
ctrl.statusMessage(uiState.message);
ctrl.statusLevel(uiState.status);
ctrl.state.on('change:value', function (e) {
var FilePicker = ComboBox.extend({
Statics: { clearHistory: clearHistory },
init: function (settings) {
var self = this, editor = getActiveEditor(), editorSettings = editor.settings;
var actionCallback, fileBrowserCallback, fileBrowserCallbackTypes;
var fileType = settings.filetype;
settings.spellcheck = false;
fileBrowserCallbackTypes = editorSettings.file_picker_types || editorSettings.file_browser_callback_types;
if (fileBrowserCallbackTypes) {
fileBrowserCallbackTypes = global$4.makeMap(fileBrowserCallbackTypes, /[, ]/);
if (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType]) {
fileBrowserCallback = editorSettings.file_picker_callback;
if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
actionCallback = function () {
var meta = self.fire('beforecall').meta;
meta = global$4.extend({ filetype: fileType }, meta);
fileBrowserCallback.call(editor, function (value, meta) {
self.value(value).fire('change', { meta: meta });
fileBrowserCallback = editorSettings.file_browser_callback;
if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
actionCallback = function () {
fileBrowserCallback(self.getEl('inp').id, self.value(), fileType, window);
settings.icon = 'browse';
settings.onaction = actionCallback;
self.classes.add('filepicker');
setupAutoCompleteHandler(self, editorSettings, editor.getBody(), fileType);
setupLinkValidatorHandler(self, editorSettings, fileType);
var FitLayout = AbsoluteLayout.extend({
recalc: function (container) {
var contLayoutRect = container.layoutRect(), paddingBox = container.paddingBox;
container.items().filter(':visible').each(function (ctrl) {
w: contLayoutRect.innerW - paddingBox.right - paddingBox.left,
h: contLayoutRect.innerH - paddingBox.top - paddingBox.bottom
var FlexLayout = AbsoluteLayout.extend({
recalc: function (container) {
var i, l, items, contLayoutRect, contPaddingBox, contSettings, align, pack, spacing, totalFlex, availableSpace, direction;
var ctrl, ctrlLayoutRect, ctrlSettings, flex;
var size, maxSize, ratio, rect, pos, maxAlignEndPos;
var sizeName, minSizeName, posName, maxSizeName, beforeName, innerSizeName, deltaSizeName, contentSizeName;
var alignAxisName, alignInnerSizeName, alignSizeName, alignMinSizeName, alignBeforeName, alignAfterName;
var alignDeltaSizeName, alignContentSizeName;
var max = Math.max, min = Math.min;
items = container.items().filter(':visible');
contLayoutRect = container.layoutRect();
contPaddingBox = container.paddingBox;
contSettings = container.settings;
direction = container.isRtl() ? contSettings.direction || 'row-reversed' : contSettings.direction;
align = contSettings.align;
pack = container.isRtl() ? contSettings.pack || 'end' : contSettings.pack;
spacing = contSettings.spacing || 0;
if (direction === 'row-reversed' || direction === 'column-reverse') {
items = items.set(items.toArray().reverse());