PageRenderTime 92ms CodeModel.GetById 43ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/js/tinymce/themes/inlite/theme.js

https://bitbucket.org/skyarch-iijima/wordpress
JavaScript | 2168 lines | 1485 code | 335 blank | 348 comment | 120 complexity | 0708be140b906ad238f8080afd1fd280 MD5 | raw file
  1. (function () {
  2. var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
  3. // Used when there is no 'main' module.
  4. // The name is probably (hopefully) unique so minification removes for releases.
  5. var register_3795 = function (id) {
  6. var module = dem(id);
  7. var fragments = id.split('.');
  8. var target = Function('return this;')();
  9. for (var i = 0; i < fragments.length - 1; ++i) {
  10. if (target[fragments[i]] === undefined)
  11. target[fragments[i]] = {};
  12. target = target[fragments[i]];
  13. }
  14. target[fragments[fragments.length - 1]] = module;
  15. };
  16. var instantiate = function (id) {
  17. var actual = defs[id];
  18. var dependencies = actual.deps;
  19. var definition = actual.defn;
  20. var len = dependencies.length;
  21. var instances = new Array(len);
  22. for (var i = 0; i < len; ++i)
  23. instances[i] = dem(dependencies[i]);
  24. var defResult = definition.apply(null, instances);
  25. if (defResult === undefined)
  26. throw 'module [' + id + '] returned undefined';
  27. actual.instance = defResult;
  28. };
  29. var def = function (id, dependencies, definition) {
  30. if (typeof id !== 'string')
  31. throw 'module id must be a string';
  32. else if (dependencies === undefined)
  33. throw 'no dependencies for ' + id;
  34. else if (definition === undefined)
  35. throw 'no definition function for ' + id;
  36. defs[id] = {
  37. deps: dependencies,
  38. defn: definition,
  39. instance: undefined
  40. };
  41. };
  42. var dem = function (id) {
  43. var actual = defs[id];
  44. if (actual === undefined)
  45. throw 'module [' + id + '] was undefined';
  46. else if (actual.instance === undefined)
  47. instantiate(id);
  48. return actual.instance;
  49. };
  50. var req = function (ids, callback) {
  51. var len = ids.length;
  52. var instances = new Array(len);
  53. for (var i = 0; i < len; ++i)
  54. instances.push(dem(ids[i]));
  55. callback.apply(null, callback);
  56. };
  57. var ephox = {};
  58. ephox.bolt = {
  59. module: {
  60. api: {
  61. define: def,
  62. require: req,
  63. demand: dem
  64. }
  65. }
  66. };
  67. var define = def;
  68. var require = req;
  69. var demand = dem;
  70. // this helps with minificiation when using a lot of global references
  71. var defineGlobal = function (id, ref) {
  72. define(id, [], function () { return ref; });
  73. };
  74. /*jsc
  75. ["tinymce.themes.inlite.Theme","tinymce.core.ThemeManager","tinymce.core.ui.Api","tinymce.core.util.Delay","tinymce.themes.inlite.alien.Arr","tinymce.themes.inlite.alien.EditorSettings","tinymce.themes.inlite.core.ElementMatcher","tinymce.themes.inlite.core.Matcher","tinymce.themes.inlite.core.PredicateId","tinymce.themes.inlite.core.SelectionMatcher","tinymce.themes.inlite.core.SkinLoader","tinymce.themes.inlite.ui.Buttons","tinymce.themes.inlite.ui.Panel","global!tinymce.util.Tools.resolve","tinymce.themes.inlite.alien.Type","tinymce.themes.inlite.core.Measure","tinymce.core.util.Tools","tinymce.core.EditorManager","tinymce.core.dom.DOMUtils","tinymce.core.ui.Factory","tinymce.themes.inlite.ui.Toolbar","tinymce.themes.inlite.ui.Forms","tinymce.themes.inlite.core.Layout","tinymce.themes.inlite.file.Conversions","tinymce.themes.inlite.file.Picker","tinymce.themes.inlite.core.Actions","tinymce.themes.inlite.core.Convert","tinymce.core.util.Promise","tinymce.themes.inlite.alien.Uuid","tinymce.themes.inlite.alien.Unlink","tinymce.themes.inlite.core.UrlType","tinymce.core.geom.Rect","tinymce.themes.inlite.alien.Bookmark","tinymce.core.dom.TreeWalker","tinymce.core.dom.RangeUtils"]
  76. jsc*/
  77. defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
  78. /**
  79. * ResolveGlobal.js
  80. *
  81. * Released under LGPL License.
  82. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  83. *
  84. * License: http://www.tinymce.com/license
  85. * Contributing: http://www.tinymce.com/contributing
  86. */
  87. define(
  88. 'tinymce.core.ThemeManager',
  89. [
  90. 'global!tinymce.util.Tools.resolve'
  91. ],
  92. function (resolve) {
  93. return resolve('tinymce.ThemeManager');
  94. }
  95. );
  96. /**
  97. * ResolveGlobal.js
  98. *
  99. * Released under LGPL License.
  100. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  101. *
  102. * License: http://www.tinymce.com/license
  103. * Contributing: http://www.tinymce.com/contributing
  104. */
  105. define(
  106. 'tinymce.core.ui.Api',
  107. [
  108. 'global!tinymce.util.Tools.resolve'
  109. ],
  110. function (resolve) {
  111. return resolve('tinymce.ui.Api');
  112. }
  113. );
  114. /**
  115. * ResolveGlobal.js
  116. *
  117. * Released under LGPL License.
  118. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  119. *
  120. * License: http://www.tinymce.com/license
  121. * Contributing: http://www.tinymce.com/contributing
  122. */
  123. define(
  124. 'tinymce.core.util.Delay',
  125. [
  126. 'global!tinymce.util.Tools.resolve'
  127. ],
  128. function (resolve) {
  129. return resolve('tinymce.util.Delay');
  130. }
  131. );
  132. /**
  133. * Arr.js
  134. *
  135. * Released under LGPL License.
  136. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  137. *
  138. * License: http://www.tinymce.com/license
  139. * Contributing: http://www.tinymce.com/contributing
  140. */
  141. define(
  142. 'tinymce.themes.inlite.alien.Arr',
  143. [
  144. ],
  145. function () {
  146. var flatten = function (arr) {
  147. return arr.reduce(function (results, item) {
  148. return Array.isArray(item) ? results.concat(flatten(item)) : results.concat(item);
  149. }, []);
  150. };
  151. return {
  152. flatten: flatten
  153. };
  154. }
  155. );
  156. /**
  157. * Type.js
  158. *
  159. * Released under LGPL License.
  160. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  161. *
  162. * License: http://www.tinymce.com/license
  163. * Contributing: http://www.tinymce.com/contributing
  164. */
  165. define(
  166. 'tinymce.themes.inlite.alien.Type',
  167. [
  168. ],
  169. function () {
  170. var isType = function (type) {
  171. return function (value) {
  172. return typeof value === type;
  173. };
  174. };
  175. var isArray = function (value) {
  176. return Array.isArray(value);
  177. };
  178. var isNull = function (value) {
  179. return value === null;
  180. };
  181. var isObject = function (predicate) {
  182. return function (value) {
  183. return !isNull(value) && !isArray(value) && predicate(value);
  184. };
  185. };
  186. return {
  187. isString: isType("string"),
  188. isNumber: isType("number"),
  189. isBoolean: isType("boolean"),
  190. isFunction: isType("function"),
  191. isObject: isObject(isType("object")),
  192. isNull: isNull,
  193. isArray: isArray
  194. };
  195. }
  196. );
  197. /**
  198. * EditorSettings.js
  199. *
  200. * Released under LGPL License.
  201. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  202. *
  203. * License: http://www.tinymce.com/license
  204. * Contributing: http://www.tinymce.com/contributing
  205. */
  206. define(
  207. 'tinymce.themes.inlite.alien.EditorSettings',
  208. [
  209. 'tinymce.themes.inlite.alien.Type'
  210. ],
  211. function (Type) {
  212. var validDefaultOrDie = function (value, predicate) {
  213. if (predicate(value)) {
  214. return true;
  215. }
  216. throw new Error('Default value doesn\'t match requested type.');
  217. };
  218. var getByTypeOr = function (predicate) {
  219. return function (editor, name, defaultValue) {
  220. var settings = editor.settings;
  221. validDefaultOrDie(defaultValue, predicate);
  222. return name in settings && predicate(settings[name]) ? settings[name] : defaultValue;
  223. };
  224. };
  225. var splitNoEmpty = function (str, delim) {
  226. return str.split(delim).filter(function (item) {
  227. return item.length > 0;
  228. });
  229. };
  230. var itemsToArray = function (value, defaultValue) {
  231. var stringToItemsArray = function (value) {
  232. return typeof value === 'string' ? splitNoEmpty(value, /[ ,]/) : value;
  233. };
  234. var boolToItemsArray = function (value, defaultValue) {
  235. return value === false ? [] : defaultValue;
  236. };
  237. if (Type.isArray(value)) {
  238. return value;
  239. } else if (Type.isString(value)) {
  240. return stringToItemsArray(value);
  241. } else if (Type.isBoolean(value)) {
  242. return boolToItemsArray(value, defaultValue);
  243. }
  244. return defaultValue;
  245. };
  246. var getToolbarItemsOr = function (predicate) {
  247. return function (editor, name, defaultValue) {
  248. var value = name in editor.settings ? editor.settings[name] : defaultValue;
  249. validDefaultOrDie(defaultValue, predicate);
  250. return itemsToArray(value, defaultValue);
  251. };
  252. };
  253. return {
  254. // TODO: Add Option based getString, getBool if merged with core
  255. getStringOr: getByTypeOr(Type.isString),
  256. getBoolOr: getByTypeOr(Type.isBoolean),
  257. getNumberOr: getByTypeOr(Type.isNumber),
  258. getHandlerOr: getByTypeOr(Type.isFunction),
  259. getToolbarItemsOr: getToolbarItemsOr(Type.isArray)
  260. };
  261. }
  262. );
  263. /**
  264. * Matcher.js
  265. *
  266. * Released under LGPL License.
  267. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  268. *
  269. * License: http://www.tinymce.com/license
  270. * Contributing: http://www.tinymce.com/contributing
  271. */
  272. define(
  273. 'tinymce.themes.inlite.core.Matcher',
  274. [
  275. ],
  276. function () {
  277. // result :: String, Rect -> Matcher.result
  278. var result = function (id, rect) {
  279. return {
  280. id: id,
  281. rect: rect
  282. };
  283. };
  284. // match :: Editor, [(Editor -> Matcher.result | Null)] -> Matcher.result | Null
  285. var match = function (editor, matchers) {
  286. for (var i = 0; i < matchers.length; i++) {
  287. var f = matchers[i];
  288. var result = f(editor);
  289. if (result) {
  290. return result;
  291. }
  292. }
  293. return null;
  294. };
  295. return {
  296. match: match,
  297. result: result
  298. };
  299. }
  300. );
  301. /**
  302. * ResolveGlobal.js
  303. *
  304. * Released under LGPL License.
  305. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  306. *
  307. * License: http://www.tinymce.com/license
  308. * Contributing: http://www.tinymce.com/contributing
  309. */
  310. define(
  311. 'tinymce.core.dom.DOMUtils',
  312. [
  313. 'global!tinymce.util.Tools.resolve'
  314. ],
  315. function (resolve) {
  316. return resolve('tinymce.dom.DOMUtils');
  317. }
  318. );
  319. /**
  320. * Convert.js
  321. *
  322. * Released under LGPL License.
  323. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  324. *
  325. * License: http://www.tinymce.com/license
  326. * Contributing: http://www.tinymce.com/contributing
  327. */
  328. define(
  329. 'tinymce.themes.inlite.core.Convert',
  330. [
  331. ],
  332. function () {
  333. var fromClientRect = function (clientRect) {
  334. return {
  335. x: clientRect.left,
  336. y: clientRect.top,
  337. w: clientRect.width,
  338. h: clientRect.height
  339. };
  340. };
  341. var toClientRect = function (geomRect) {
  342. return {
  343. left: geomRect.x,
  344. top: geomRect.y,
  345. width: geomRect.w,
  346. height: geomRect.h,
  347. right: geomRect.x + geomRect.w,
  348. bottom: geomRect.y + geomRect.h
  349. };
  350. };
  351. return {
  352. fromClientRect: fromClientRect,
  353. toClientRect: toClientRect
  354. };
  355. }
  356. );
  357. /**
  358. * Measure.js
  359. *
  360. * Released under LGPL License.
  361. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  362. *
  363. * License: http://www.tinymce.com/license
  364. * Contributing: http://www.tinymce.com/contributing
  365. */
  366. define(
  367. 'tinymce.themes.inlite.core.Measure',
  368. [
  369. 'tinymce.core.dom.DOMUtils',
  370. 'tinymce.themes.inlite.core.Convert'
  371. ],
  372. function (DOMUtils, Convert) {
  373. var toAbsolute = function (rect) {
  374. var vp = DOMUtils.DOM.getViewPort();
  375. return {
  376. x: rect.x + vp.x,
  377. y: rect.y + vp.y,
  378. w: rect.w,
  379. h: rect.h
  380. };
  381. };
  382. var measureElement = function (elm) {
  383. var clientRect = elm.getBoundingClientRect();
  384. return toAbsolute({
  385. x: clientRect.left,
  386. y: clientRect.top,
  387. w: Math.max(elm.clientWidth, elm.offsetWidth),
  388. h: Math.max(elm.clientHeight, elm.offsetHeight)
  389. });
  390. };
  391. var getElementRect = function (editor, elm) {
  392. return measureElement(elm);
  393. };
  394. var getPageAreaRect = function (editor) {
  395. return measureElement(editor.getElement().ownerDocument.body);
  396. };
  397. var getContentAreaRect = function (editor) {
  398. return measureElement(editor.getContentAreaContainer() || editor.getBody());
  399. };
  400. var getSelectionRect = function (editor) {
  401. var clientRect = editor.selection.getBoundingClientRect();
  402. return clientRect ? toAbsolute(Convert.fromClientRect(clientRect)) : null;
  403. };
  404. return {
  405. getElementRect: getElementRect,
  406. getPageAreaRect: getPageAreaRect,
  407. getContentAreaRect: getContentAreaRect,
  408. getSelectionRect: getSelectionRect
  409. };
  410. }
  411. );
  412. /**
  413. * ElementMatcher.js
  414. *
  415. * Released under LGPL License.
  416. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  417. *
  418. * License: http://www.tinymce.com/license
  419. * Contributing: http://www.tinymce.com/contributing
  420. */
  421. define(
  422. 'tinymce.themes.inlite.core.ElementMatcher',
  423. [
  424. 'tinymce.themes.inlite.core.Matcher',
  425. 'tinymce.themes.inlite.core.Measure'
  426. ],
  427. function (Matcher, Measure) {
  428. // element :: Element, [PredicateId] -> (Editor -> Matcher.result | Null)
  429. var element = function (element, predicateIds) {
  430. return function (editor) {
  431. for (var i = 0; i < predicateIds.length; i++) {
  432. if (predicateIds[i].predicate(element)) {
  433. return Matcher.result(predicateIds[i].id, Measure.getElementRect(editor, element));
  434. }
  435. }
  436. return null;
  437. };
  438. };
  439. // parent :: [Elements], [PredicateId] -> (Editor -> Matcher.result | Null)
  440. var parent = function (elements, predicateIds) {
  441. return function (editor) {
  442. for (var i = 0; i < elements.length; i++) {
  443. for (var x = 0; x < predicateIds.length; x++) {
  444. if (predicateIds[x].predicate(elements[i])) {
  445. return Matcher.result(predicateIds[x].id, Measure.getElementRect(editor, elements[i]));
  446. }
  447. }
  448. }
  449. return null;
  450. };
  451. };
  452. return {
  453. element: element,
  454. parent: parent
  455. };
  456. }
  457. );
  458. /**
  459. * ResolveGlobal.js
  460. *
  461. * Released under LGPL License.
  462. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  463. *
  464. * License: http://www.tinymce.com/license
  465. * Contributing: http://www.tinymce.com/contributing
  466. */
  467. define(
  468. 'tinymce.core.util.Tools',
  469. [
  470. 'global!tinymce.util.Tools.resolve'
  471. ],
  472. function (resolve) {
  473. return resolve('tinymce.util.Tools');
  474. }
  475. );
  476. /**
  477. * PredicateId.js
  478. *
  479. * Released under LGPL License.
  480. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  481. *
  482. * License: http://www.tinymce.com/license
  483. * Contributing: http://www.tinymce.com/contributing
  484. */
  485. define(
  486. 'tinymce.themes.inlite.core.PredicateId',
  487. [
  488. 'tinymce.core.util.Tools'
  489. ],
  490. function (Tools) {
  491. var create = function (id, predicate) {
  492. return {
  493. id: id,
  494. predicate: predicate
  495. };
  496. };
  497. // fromContextToolbars :: [ContextToolbar] -> [PredicateId]
  498. var fromContextToolbars = function (toolbars) {
  499. return Tools.map(toolbars, function (toolbar) {
  500. return create(toolbar.id, toolbar.predicate);
  501. });
  502. };
  503. return {
  504. create: create,
  505. fromContextToolbars: fromContextToolbars
  506. };
  507. }
  508. );
  509. /**
  510. * SelectionMatcher.js
  511. *
  512. * Released under LGPL License.
  513. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  514. *
  515. * License: http://www.tinymce.com/license
  516. * Contributing: http://www.tinymce.com/contributing
  517. */
  518. define(
  519. 'tinymce.themes.inlite.core.SelectionMatcher',
  520. [
  521. 'tinymce.themes.inlite.core.Matcher',
  522. 'tinymce.themes.inlite.core.Measure'
  523. ],
  524. function (Matcher, Measure) {
  525. // textSelection :: String -> (Editor -> Matcher.result | Null)
  526. var textSelection = function (id) {
  527. return function (editor) {
  528. if (!editor.selection.isCollapsed()) {
  529. return Matcher.result(id, Measure.getSelectionRect(editor));
  530. }
  531. return null;
  532. };
  533. };
  534. // emptyTextBlock :: [Elements], String -> (Editor -> Matcher.result | Null)
  535. var emptyTextBlock = function (elements, id) {
  536. return function (editor) {
  537. var i, textBlockElementsMap = editor.schema.getTextBlockElements();
  538. for (i = 0; i < elements.length; i++) {
  539. if (elements[i].nodeName === 'TABLE') {
  540. return null;
  541. }
  542. }
  543. for (i = 0; i < elements.length; i++) {
  544. if (elements[i].nodeName in textBlockElementsMap) {
  545. if (editor.dom.isEmpty(elements[i])) {
  546. return Matcher.result(id, Measure.getSelectionRect(editor));
  547. }
  548. return null;
  549. }
  550. }
  551. return null;
  552. };
  553. };
  554. return {
  555. textSelection: textSelection,
  556. emptyTextBlock: emptyTextBlock
  557. };
  558. }
  559. );
  560. /**
  561. * ResolveGlobal.js
  562. *
  563. * Released under LGPL License.
  564. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  565. *
  566. * License: http://www.tinymce.com/license
  567. * Contributing: http://www.tinymce.com/contributing
  568. */
  569. define(
  570. 'tinymce.core.EditorManager',
  571. [
  572. 'global!tinymce.util.Tools.resolve'
  573. ],
  574. function (resolve) {
  575. return resolve('tinymce.EditorManager');
  576. }
  577. );
  578. /**
  579. * SkinLoader.js
  580. *
  581. * Released under LGPL License.
  582. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  583. *
  584. * License: http://www.tinymce.com/license
  585. * Contributing: http://www.tinymce.com/contributing
  586. */
  587. define(
  588. 'tinymce.themes.inlite.core.SkinLoader',
  589. [
  590. 'tinymce.core.EditorManager',
  591. 'tinymce.core.dom.DOMUtils'
  592. ],
  593. function (EditorManager, DOMUtils) {
  594. var fireSkinLoaded = function (editor, callback) {
  595. var done = function () {
  596. editor._skinLoaded = true;
  597. editor.fire('SkinLoaded');
  598. callback();
  599. };
  600. if (editor.initialized) {
  601. done();
  602. } else {
  603. editor.on('init', done);
  604. }
  605. };
  606. var urlFromName = function (name) {
  607. var prefix = EditorManager.baseURL + '/skins/';
  608. return name ? prefix + name : prefix + 'lightgray';
  609. };
  610. var toAbsoluteUrl = function (editor, url) {
  611. return editor.documentBaseURI.toAbsolute(url);
  612. };
  613. var load = function (editor, callback) {
  614. var settings = editor.settings;
  615. var skinUrl = settings.skin_url ? toAbsoluteUrl(editor, settings.skin_url) : urlFromName(settings.skin);
  616. var done = function () {
  617. fireSkinLoaded(editor, callback);
  618. };
  619. DOMUtils.DOM.styleSheetLoader.load(skinUrl + '/skin.min.css', done);
  620. editor.contentCSS.push(skinUrl + '/content.inline.min.css');
  621. };
  622. return {
  623. load: load
  624. };
  625. }
  626. );
  627. /**
  628. * ResolveGlobal.js
  629. *
  630. * Released under LGPL License.
  631. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  632. *
  633. * License: http://www.tinymce.com/license
  634. * Contributing: http://www.tinymce.com/contributing
  635. */
  636. define(
  637. 'tinymce.core.ui.Factory',
  638. [
  639. 'global!tinymce.util.Tools.resolve'
  640. ],
  641. function (resolve) {
  642. return resolve('tinymce.ui.Factory');
  643. }
  644. );
  645. /**
  646. * Toolbar.js
  647. *
  648. * Released under LGPL License.
  649. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  650. *
  651. * License: http://www.tinymce.com/license
  652. * Contributing: http://www.tinymce.com/contributing
  653. */
  654. define(
  655. 'tinymce.themes.inlite.ui.Toolbar',
  656. [
  657. 'tinymce.core.util.Tools',
  658. 'tinymce.core.ui.Factory',
  659. 'tinymce.themes.inlite.alien.Type'
  660. ],
  661. function (Tools, Factory, Type) {
  662. var getSelectorStateResult = function (itemName, item) {
  663. var result = function (selector, handler) {
  664. return {
  665. selector: selector,
  666. handler: handler
  667. };
  668. };
  669. var activeHandler = function (state) {
  670. item.active(state);
  671. };
  672. var disabledHandler = function (state) {
  673. item.disabled(state);
  674. };
  675. if (item.settings.stateSelector) {
  676. return result(item.settings.stateSelector, activeHandler);
  677. }
  678. if (item.settings.disabledStateSelector) {
  679. return result(item.settings.disabledStateSelector, disabledHandler);
  680. }
  681. return null;
  682. };
  683. var bindSelectorChanged = function (editor, itemName, item) {
  684. return function () {
  685. var result = getSelectorStateResult(itemName, item);
  686. if (result !== null) {
  687. editor.selection.selectorChanged(result.selector, result.handler);
  688. }
  689. };
  690. };
  691. var itemsToArray = function (items) {
  692. if (Type.isArray(items)) {
  693. return items;
  694. } else if (Type.isString(items)) {
  695. return items.split(/[ ,]/);
  696. }
  697. return [];
  698. };
  699. var create = function (editor, name, items) {
  700. var toolbarItems = [], buttonGroup;
  701. if (!items) {
  702. return;
  703. }
  704. Tools.each(itemsToArray(items), function (item) {
  705. var itemName;
  706. if (item == '|') {
  707. buttonGroup = null;
  708. } else {
  709. if (editor.buttons[item]) {
  710. if (!buttonGroup) {
  711. buttonGroup = { type: 'buttongroup', items: [] };
  712. toolbarItems.push(buttonGroup);
  713. }
  714. itemName = item;
  715. item = editor.buttons[itemName];
  716. if (typeof item == 'function') {
  717. item = item();
  718. }
  719. item.type = item.type || 'button';
  720. item = Factory.create(item);
  721. item.on('postRender', bindSelectorChanged(editor, itemName, item));
  722. buttonGroup.items.push(item);
  723. }
  724. }
  725. });
  726. return Factory.create({
  727. type: 'toolbar',
  728. layout: 'flow',
  729. name: name,
  730. items: toolbarItems
  731. });
  732. };
  733. return {
  734. create: create
  735. };
  736. }
  737. );
  738. /**
  739. * ResolveGlobal.js
  740. *
  741. * Released under LGPL License.
  742. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  743. *
  744. * License: http://www.tinymce.com/license
  745. * Contributing: http://www.tinymce.com/contributing
  746. */
  747. define(
  748. 'tinymce.core.util.Promise',
  749. [
  750. 'global!tinymce.util.Tools.resolve'
  751. ],
  752. function (resolve) {
  753. return resolve('tinymce.util.Promise');
  754. }
  755. );
  756. /**
  757. * Uuid.js
  758. *
  759. * Released under LGPL License.
  760. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  761. *
  762. * License: http://www.tinymce.com/license
  763. * Contributing: http://www.tinymce.com/contributing
  764. */
  765. /**
  766. * Generates unique ids this is the same as in core but since
  767. * it's not exposed as a global we can't access it.
  768. */
  769. define(
  770. "tinymce.themes.inlite.alien.Uuid",
  771. [
  772. ],
  773. function () {
  774. var count = 0;
  775. var seed = function () {
  776. var rnd = function () {
  777. return Math.round(Math.random() * 0xFFFFFFFF).toString(36);
  778. };
  779. return 's' + Date.now().toString(36) + rnd() + rnd() + rnd();
  780. };
  781. var uuid = function (prefix) {
  782. return prefix + (count++) + seed();
  783. };
  784. return {
  785. uuid: uuid
  786. };
  787. }
  788. );
  789. /**
  790. * Bookmark.js
  791. *
  792. * Released under LGPL License.
  793. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  794. *
  795. * License: http://www.tinymce.com/license
  796. * Contributing: http://www.tinymce.com/contributing
  797. */
  798. define(
  799. 'tinymce.themes.inlite.alien.Bookmark',
  800. [
  801. ],
  802. function () {
  803. /**
  804. * Returns a range bookmark. This will convert indexed bookmarks into temporary span elements with
  805. * index 0 so that they can be restored properly after the DOM has been modified. Text bookmarks will not have spans
  806. * added to them since they can be restored after a dom operation.
  807. *
  808. * So this: <p><b>|</b><b>|</b></p>
  809. * becomes: <p><b><span data-mce-type="bookmark">|</span></b><b data-mce-type="bookmark">|</span></b></p>
  810. *
  811. * @param {DOMRange} rng DOM Range to get bookmark on.
  812. * @return {Object} Bookmark object.
  813. */
  814. var create = function (dom, rng) {
  815. var bookmark = {};
  816. function setupEndPoint(start) {
  817. var offsetNode, container, offset;
  818. container = rng[start ? 'startContainer' : 'endContainer'];
  819. offset = rng[start ? 'startOffset' : 'endOffset'];
  820. if (container.nodeType == 1) {
  821. offsetNode = dom.create('span', { 'data-mce-type': 'bookmark' });
  822. if (container.hasChildNodes()) {
  823. offset = Math.min(offset, container.childNodes.length - 1);
  824. if (start) {
  825. container.insertBefore(offsetNode, container.childNodes[offset]);
  826. } else {
  827. dom.insertAfter(offsetNode, container.childNodes[offset]);
  828. }
  829. } else {
  830. container.appendChild(offsetNode);
  831. }
  832. container = offsetNode;
  833. offset = 0;
  834. }
  835. bookmark[start ? 'startContainer' : 'endContainer'] = container;
  836. bookmark[start ? 'startOffset' : 'endOffset'] = offset;
  837. }
  838. setupEndPoint(true);
  839. if (!rng.collapsed) {
  840. setupEndPoint();
  841. }
  842. return bookmark;
  843. };
  844. /**
  845. * Moves the selection to the current bookmark and removes any selection container wrappers.
  846. *
  847. * @param {Object} bookmark Bookmark object to move selection to.
  848. */
  849. var resolve = function (dom, bookmark) {
  850. function restoreEndPoint(start) {
  851. var container, offset, node;
  852. function nodeIndex(container) {
  853. var node = container.parentNode.firstChild, idx = 0;
  854. while (node) {
  855. if (node == container) {
  856. return idx;
  857. }
  858. // Skip data-mce-type=bookmark nodes
  859. if (node.nodeType != 1 || node.getAttribute('data-mce-type') != 'bookmark') {
  860. idx++;
  861. }
  862. node = node.nextSibling;
  863. }
  864. return -1;
  865. }
  866. container = node = bookmark[start ? 'startContainer' : 'endContainer'];
  867. offset = bookmark[start ? 'startOffset' : 'endOffset'];
  868. if (!container) {
  869. return;
  870. }
  871. if (container.nodeType == 1) {
  872. offset = nodeIndex(container);
  873. container = container.parentNode;
  874. dom.remove(node);
  875. }
  876. bookmark[start ? 'startContainer' : 'endContainer'] = container;
  877. bookmark[start ? 'startOffset' : 'endOffset'] = offset;
  878. }
  879. restoreEndPoint(true);
  880. restoreEndPoint();
  881. var rng = dom.createRng();
  882. rng.setStart(bookmark.startContainer, bookmark.startOffset);
  883. if (bookmark.endContainer) {
  884. rng.setEnd(bookmark.endContainer, bookmark.endOffset);
  885. }
  886. return rng;
  887. };
  888. return {
  889. create: create,
  890. resolve: resolve
  891. };
  892. }
  893. );
  894. /**
  895. * ResolveGlobal.js
  896. *
  897. * Released under LGPL License.
  898. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  899. *
  900. * License: http://www.tinymce.com/license
  901. * Contributing: http://www.tinymce.com/contributing
  902. */
  903. define(
  904. 'tinymce.core.dom.TreeWalker',
  905. [
  906. 'global!tinymce.util.Tools.resolve'
  907. ],
  908. function (resolve) {
  909. return resolve('tinymce.dom.TreeWalker');
  910. }
  911. );
  912. /**
  913. * ResolveGlobal.js
  914. *
  915. * Released under LGPL License.
  916. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  917. *
  918. * License: http://www.tinymce.com/license
  919. * Contributing: http://www.tinymce.com/contributing
  920. */
  921. define(
  922. 'tinymce.core.dom.RangeUtils',
  923. [
  924. 'global!tinymce.util.Tools.resolve'
  925. ],
  926. function (resolve) {
  927. return resolve('tinymce.dom.RangeUtils');
  928. }
  929. );
  930. /**
  931. * Unlink.js
  932. *
  933. * Released under LGPL License.
  934. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  935. *
  936. * License: http://www.tinymce.com/license
  937. * Contributing: http://www.tinymce.com/contributing
  938. */
  939. /**
  940. * Unlink implementation that doesn't leave partial links for example it would produce:
  941. * a[b<a href="x">c]d</a>e -> a[bc]de
  942. * instead of:
  943. * a[b<a href="x">c]d</a>e -> a[bc]<a href="x">d</a>e
  944. */
  945. define(
  946. "tinymce.themes.inlite.alien.Unlink",
  947. [
  948. 'tinymce.themes.inlite.alien.Bookmark',
  949. 'tinymce.core.util.Tools',
  950. 'tinymce.core.dom.TreeWalker',
  951. 'tinymce.core.dom.RangeUtils'
  952. ],
  953. function (Bookmark, Tools, TreeWalker, RangeUtils) {
  954. var getSelectedElements = function (rootElm, startNode, endNode) {
  955. var walker, node, elms = [];
  956. walker = new TreeWalker(startNode, rootElm);
  957. for (node = startNode; node; node = walker.next()) {
  958. if (node.nodeType === 1) {
  959. elms.push(node);
  960. }
  961. if (node === endNode) {
  962. break;
  963. }
  964. }
  965. return elms;
  966. };
  967. var unwrapElements = function (editor, elms) {
  968. var bookmark, dom, selection;
  969. dom = editor.dom;
  970. selection = editor.selection;
  971. bookmark = Bookmark.create(dom, selection.getRng());
  972. Tools.each(elms, function (elm) {
  973. editor.dom.remove(elm, true);
  974. });
  975. selection.setRng(Bookmark.resolve(dom, bookmark));
  976. };
  977. var isLink = function (elm) {
  978. return elm.nodeName === 'A' && elm.hasAttribute('href');
  979. };
  980. var getParentAnchorOrSelf = function (dom, elm) {
  981. var anchorElm = dom.getParent(elm, isLink);
  982. return anchorElm ? anchorElm : elm;
  983. };
  984. var getSelectedAnchors = function (editor) {
  985. var startElm, endElm, rootElm, anchorElms, selection, dom, rng;
  986. selection = editor.selection;
  987. dom = editor.dom;
  988. rng = selection.getRng();
  989. startElm = getParentAnchorOrSelf(dom, RangeUtils.getNode(rng.startContainer, rng.startOffset));
  990. endElm = RangeUtils.getNode(rng.endContainer, rng.endOffset);
  991. rootElm = editor.getBody();
  992. anchorElms = Tools.grep(getSelectedElements(rootElm, startElm, endElm), isLink);
  993. return anchorElms;
  994. };
  995. var unlinkSelection = function (editor) {
  996. unwrapElements(editor, getSelectedAnchors(editor));
  997. };
  998. return {
  999. unlinkSelection: unlinkSelection
  1000. };
  1001. }
  1002. );
  1003. /**
  1004. * Actions.js
  1005. *
  1006. * Released under LGPL License.
  1007. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1008. *
  1009. * License: http://www.tinymce.com/license
  1010. * Contributing: http://www.tinymce.com/contributing
  1011. */
  1012. define(
  1013. 'tinymce.themes.inlite.core.Actions',
  1014. [
  1015. 'tinymce.themes.inlite.alien.Uuid',
  1016. 'tinymce.themes.inlite.alien.Unlink'
  1017. ],
  1018. function (Uuid, Unlink) {
  1019. var createTableHtml = function (cols, rows) {
  1020. var x, y, html;
  1021. html = '<table data-mce-id="mce" style="width: 100%">';
  1022. html += '<tbody>';
  1023. for (y = 0; y < rows; y++) {
  1024. html += '<tr>';
  1025. for (x = 0; x < cols; x++) {
  1026. html += '<td><br></td>';
  1027. }
  1028. html += '</tr>';
  1029. }
  1030. html += '</tbody>';
  1031. html += '</table>';
  1032. return html;
  1033. };
  1034. var getInsertedElement = function (editor) {
  1035. var elms = editor.dom.select('*[data-mce-id]');
  1036. return elms[0];
  1037. };
  1038. var insertTable = function (editor, cols, rows) {
  1039. editor.undoManager.transact(function () {
  1040. var tableElm, cellElm;
  1041. editor.insertContent(createTableHtml(cols, rows));
  1042. tableElm = getInsertedElement(editor);
  1043. tableElm.removeAttribute('data-mce-id');
  1044. cellElm = editor.dom.select('td,th', tableElm);
  1045. editor.selection.setCursorLocation(cellElm[0], 0);
  1046. });
  1047. };
  1048. var formatBlock = function (editor, formatName) {
  1049. editor.execCommand('FormatBlock', false, formatName);
  1050. };
  1051. var insertBlob = function (editor, base64, blob) {
  1052. var blobCache, blobInfo;
  1053. blobCache = editor.editorUpload.blobCache;
  1054. blobInfo = blobCache.create(Uuid.uuid('mceu'), blob, base64);
  1055. blobCache.add(blobInfo);
  1056. editor.insertContent(editor.dom.createHTML('img', { src: blobInfo.blobUri() }));
  1057. };
  1058. var collapseSelectionToEnd = function (editor) {
  1059. editor.selection.collapse(false);
  1060. };
  1061. var unlink = function (editor) {
  1062. editor.focus();
  1063. Unlink.unlinkSelection(editor);
  1064. collapseSelectionToEnd(editor);
  1065. };
  1066. var changeHref = function (editor, elm, url) {
  1067. editor.focus();
  1068. editor.dom.setAttrib(elm, 'href', url);
  1069. collapseSelectionToEnd(editor);
  1070. };
  1071. var insertLink = function (editor, url) {
  1072. editor.execCommand('mceInsertLink', false, { href: url });
  1073. collapseSelectionToEnd(editor);
  1074. };
  1075. var updateOrInsertLink = function (editor, url) {
  1076. var elm = editor.dom.getParent(editor.selection.getStart(), 'a[href]');
  1077. elm ? changeHref(editor, elm, url) : insertLink(editor, url);
  1078. };
  1079. var createLink = function (editor, url) {
  1080. url.trim().length === 0 ? unlink(editor) : updateOrInsertLink(editor, url);
  1081. };
  1082. return {
  1083. insertTable: insertTable,
  1084. formatBlock: formatBlock,
  1085. insertBlob: insertBlob,
  1086. createLink: createLink,
  1087. unlink: unlink
  1088. };
  1089. }
  1090. );
  1091. /**
  1092. * UrlType.js
  1093. *
  1094. * Released under LGPL License.
  1095. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1096. *
  1097. * License: http://www.tinymce.com/license
  1098. * Contributing: http://www.tinymce.com/contributing
  1099. */
  1100. define(
  1101. 'tinymce.themes.inlite.core.UrlType',
  1102. [
  1103. ],
  1104. function () {
  1105. var isDomainLike = function (href) {
  1106. 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());
  1107. };
  1108. var isAbsolute = function (href) {
  1109. return /^https?:\/\//.test(href.trim());
  1110. };
  1111. return {
  1112. isDomainLike: isDomainLike,
  1113. isAbsolute: isAbsolute
  1114. };
  1115. }
  1116. );
  1117. /**
  1118. * Forms.js
  1119. *
  1120. * Released under LGPL License.
  1121. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1122. *
  1123. * License: http://www.tinymce.com/license
  1124. * Contributing: http://www.tinymce.com/contributing
  1125. */
  1126. define(
  1127. 'tinymce.themes.inlite.ui.Forms',
  1128. [
  1129. 'tinymce.core.util.Tools',
  1130. 'tinymce.core.ui.Factory',
  1131. 'tinymce.core.util.Promise',
  1132. 'tinymce.themes.inlite.core.Actions',
  1133. 'tinymce.themes.inlite.core.UrlType'
  1134. ],
  1135. function (Tools, Factory, Promise, Actions, UrlType) {
  1136. var focusFirstTextBox = function (form) {
  1137. form.find('textbox').eq(0).each(function (ctrl) {
  1138. ctrl.focus();
  1139. });
  1140. };
  1141. var createForm = function (name, spec) {
  1142. var form = Factory.create(
  1143. Tools.extend({
  1144. type: 'form',
  1145. layout: 'flex',
  1146. direction: 'row',
  1147. padding: 5,
  1148. name: name,
  1149. spacing: 3
  1150. }, spec)
  1151. );
  1152. form.on('show', function () {
  1153. focusFirstTextBox(form);
  1154. });
  1155. return form;
  1156. };
  1157. var toggleVisibility = function (ctrl, state) {
  1158. return state ? ctrl.show() : ctrl.hide();
  1159. };
  1160. var askAboutPrefix = function (editor, href) {
  1161. return new Promise(function (resolve) {
  1162. editor.windowManager.confirm(
  1163. 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?',
  1164. function (result) {
  1165. var output = result === true ? 'http://' + href : href;
  1166. resolve(output);
  1167. }
  1168. );
  1169. });
  1170. };
  1171. var convertLinkToAbsolute = function (editor, href) {
  1172. return !UrlType.isAbsolute(href) && UrlType.isDomainLike(href) ? askAboutPrefix(editor, href) : Promise.resolve(href);
  1173. };
  1174. var createQuickLinkForm = function (editor, hide) {
  1175. var attachState = {};
  1176. var unlink = function () {
  1177. editor.focus();
  1178. Actions.unlink(editor);
  1179. hide();
  1180. };
  1181. var onChangeHandler = function (e) {
  1182. var meta = e.meta;
  1183. if (meta && meta.attach) {
  1184. attachState = {
  1185. href: this.value(),
  1186. attach: meta.attach
  1187. };
  1188. }
  1189. };
  1190. var onShowHandler = function (e) {
  1191. if (e.control === this) {
  1192. var elm, linkurl = '';
  1193. elm = editor.dom.getParent(editor.selection.getStart(), 'a[href]');
  1194. if (elm) {
  1195. linkurl = editor.dom.getAttrib(elm, 'href');
  1196. }
  1197. this.fromJSON({
  1198. linkurl: linkurl
  1199. });
  1200. toggleVisibility(this.find('#unlink'), elm);
  1201. this.find('#linkurl')[0].focus();
  1202. }
  1203. };
  1204. return createForm('quicklink', {
  1205. items: [
  1206. { type: 'button', name: 'unlink', icon: 'unlink', onclick: unlink, tooltip: 'Remove link' },
  1207. { type: 'filepicker', name: 'linkurl', placeholder: 'Paste or type a link', filetype: 'file', onchange: onChangeHandler },
  1208. { type: 'button', icon: 'checkmark', subtype: 'primary', tooltip: 'Ok', onclick: 'submit' }
  1209. ],
  1210. onshow: onShowHandler,
  1211. onsubmit: function (e) {
  1212. convertLinkToAbsolute(editor, e.data.linkurl).then(function (url) {
  1213. editor.undoManager.transact(function () {
  1214. if (url === attachState.href) {
  1215. attachState.attach();
  1216. attachState = {};
  1217. }
  1218. Actions.createLink(editor, url);
  1219. });
  1220. hide();
  1221. });
  1222. }
  1223. });
  1224. };
  1225. return {
  1226. createQuickLinkForm: createQuickLinkForm
  1227. };
  1228. }
  1229. );
  1230. /**
  1231. * ResolveGlobal.js
  1232. *
  1233. * Released under LGPL License.
  1234. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
  1235. *
  1236. * License: http://www.tinymce.com/license
  1237. * Contributing: http://www.tinymce.com/contributing
  1238. */
  1239. define(
  1240. 'tinymce.core.geom.Rect',
  1241. [
  1242. 'global!tinymce.util.Tools.resolve'
  1243. ],
  1244. function (resolve) {
  1245. return resolve('tinymce.geom.Rect');
  1246. }
  1247. );
  1248. /**
  1249. * Layout.js
  1250. *
  1251. * Released under LGPL License.
  1252. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1253. *
  1254. * License: http://www.tinymce.com/license
  1255. * Contributing: http://www.tinymce.com/contributing
  1256. */
  1257. define(
  1258. 'tinymce.themes.inlite.core.Layout',
  1259. [
  1260. 'tinymce.core.geom.Rect',
  1261. 'tinymce.themes.inlite.core.Convert'
  1262. ],
  1263. function (Rect, Convert) {
  1264. var result = function (rect, position) {
  1265. return {
  1266. rect: rect,
  1267. position: position
  1268. };
  1269. };
  1270. var moveTo = function (rect, toRect) {
  1271. return { x: toRect.x, y: toRect.y, w: rect.w, h: rect.h };
  1272. };
  1273. var calcByPositions = function (testPositions1, testPositions2, targetRect, contentAreaRect, panelRect) {
  1274. var relPos, relRect, outputPanelRect;
  1275. var paddedContentRect = {
  1276. x: contentAreaRect.x,
  1277. y: contentAreaRect.y,
  1278. w: contentAreaRect.w + (contentAreaRect.w < (panelRect.w + targetRect.w) ? panelRect.w : 0),
  1279. h: contentAreaRect.h + (contentAreaRect.h < (panelRect.h + targetRect.h) ? panelRect.h : 0)
  1280. };
  1281. relPos = Rect.findBestRelativePosition(panelRect, targetRect, paddedContentRect, testPositions1);
  1282. targetRect = Rect.clamp(targetRect, paddedContentRect);
  1283. if (relPos) {
  1284. relRect = Rect.relativePosition(panelRect, targetRect, relPos);
  1285. outputPanelRect = moveTo(panelRect, relRect);
  1286. return result(outputPanelRect, relPos);
  1287. }
  1288. targetRect = Rect.intersect(paddedContentRect, targetRect);
  1289. if (targetRect) {
  1290. relPos = Rect.findBestRelativePosition(panelRect, targetRect, paddedContentRect, testPositions2);
  1291. if (relPos) {
  1292. relRect = Rect.relativePosition(panelRect, targetRect, relPos);
  1293. outputPanelRect = moveTo(panelRect, relRect);
  1294. return result(outputPanelRect, relPos);
  1295. }
  1296. outputPanelRect = moveTo(panelRect, targetRect);
  1297. return result(outputPanelRect, relPos);
  1298. }
  1299. return null;
  1300. };
  1301. var calcInsert = function (targetRect, contentAreaRect, panelRect) {
  1302. return calcByPositions(
  1303. ['cr-cl', 'cl-cr'],
  1304. ['bc-tc', 'bl-tl', 'br-tr'],
  1305. targetRect,
  1306. contentAreaRect,
  1307. panelRect
  1308. );
  1309. };
  1310. var calc = function (targetRect, contentAreaRect, panelRect) {
  1311. return calcByPositions(
  1312. ['tc-bc', 'bc-tc', 'tl-bl', 'bl-tl', 'tr-br', 'br-tr', 'cr-cl', 'cl-cr'],
  1313. ['bc-tc', 'bl-tl', 'br-tr', 'cr-cl'],
  1314. targetRect,
  1315. contentAreaRect,
  1316. panelRect
  1317. );
  1318. };
  1319. var userConstrain = function (handler, targetRect, contentAreaRect, panelRect) {
  1320. var userConstrainedPanelRect;
  1321. if (typeof handler === 'function') {
  1322. userConstrainedPanelRect = handler({
  1323. elementRect: Convert.toClientRect(targetRect),
  1324. contentAreaRect: Convert.toClientRect(contentAreaRect),
  1325. panelRect: Convert.toClientRect(panelRect)
  1326. });
  1327. return Convert.fromClientRect(userConstrainedPanelRect);
  1328. }
  1329. return panelRect;
  1330. };
  1331. var defaultHandler = function (rects) {
  1332. return rects.panelRect;
  1333. };
  1334. return {
  1335. calcInsert: calcInsert,
  1336. calc: calc,
  1337. userConstrain: userConstrain,
  1338. defaultHandler: defaultHandler
  1339. };
  1340. }
  1341. );
  1342. /**
  1343. * Panel.js
  1344. *
  1345. * Released under LGPL License.
  1346. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1347. *
  1348. * License: http://www.tinymce.com/license
  1349. * Contributing: http://www.tinymce.com/contributing
  1350. */
  1351. define(
  1352. 'tinymce.themes.inlite.ui.Panel',
  1353. [
  1354. 'tinymce.core.util.Tools',
  1355. 'tinymce.core.ui.Factory',
  1356. 'tinymce.core.dom.DOMUtils',
  1357. 'tinymce.themes.inlite.ui.Toolbar',
  1358. 'tinymce.themes.inlite.ui.Forms',
  1359. 'tinymce.themes.inlite.core.Measure',
  1360. 'tinymce.themes.inlite.core.Layout',
  1361. 'tinymce.themes.inlite.alien.EditorSettings'
  1362. ],
  1363. function (Tools, Factory, DOMUtils, Toolbar, Forms, Measure, Layout, EditorSettings) {
  1364. return function () {
  1365. var DEFAULT_TEXT_SELECTION_ITEMS = ['bold', 'italic', '|', 'quicklink', 'h2', 'h3', 'blockquote'];
  1366. var DEFAULT_INSERT_TOOLBAR_ITEMS = ['quickimage', 'quicktable'];
  1367. var panel, currentRect;
  1368. var createToolbars = function (editor, toolbars) {
  1369. return Tools.map(toolbars, function (toolbar) {
  1370. return Toolbar.create(editor, toolbar.id, toolbar.items);
  1371. });
  1372. };
  1373. var getTextSelectionToolbarItems = function (editor) {
  1374. return EditorSettings.getToolbarItemsOr(editor, 'selection_toolbar', DEFAULT_TEXT_SELECTION_ITEMS);
  1375. };
  1376. var getInsertToolbarItems = function (editor) {
  1377. return EditorSettings.getToolbarItemsOr(editor, 'insert_toolbar', DEFAULT_INSERT_TOOLBAR_ITEMS);
  1378. };
  1379. var hasToolbarItems = function (toolbar) {
  1380. return toolbar.items().length > 0;
  1381. };
  1382. var create = function (editor, toolbars) {
  1383. var items = createToolbars(editor, toolbars).concat([
  1384. Toolbar.create(editor, 'text', getTextSelectionToolbarItems(editor)),
  1385. Toolbar.create(editor, 'insert', getInsertToolbarItems(editor)),
  1386. Forms.createQuickLinkForm(editor, hide)
  1387. ]);
  1388. return Factory.create({
  1389. type: 'floatpanel',
  1390. role: 'dialog',
  1391. classes: 'tinymce tinymce-inline arrow',
  1392. ariaLabel: 'Inline toolbar',
  1393. layout: 'flex',
  1394. direction: 'column',
  1395. align: 'stretch',
  1396. autohide: false,
  1397. autofix: true,
  1398. fixed: true,
  1399. border: 1,
  1400. items: Tools.grep(items, hasToolbarItems),
  1401. oncancel: function () {
  1402. editor.focus();
  1403. }
  1404. });
  1405. };
  1406. var showPanel = function (panel) {
  1407. if (panel) {
  1408. panel.show();
  1409. }
  1410. };
  1411. var movePanelTo = function (panel, pos) {
  1412. panel.moveTo(pos.x, pos.y);
  1413. };
  1414. var togglePositionClass = function (panel, relPos) {
  1415. relPos = relPos ? relPos.substr(0, 2) : '';
  1416. Tools.each({
  1417. t: 'down',
  1418. b: 'up',
  1419. c: 'center'
  1420. }, function (cls, pos) {
  1421. panel.classes.toggle('arrow-' + cls, pos === relPos.substr(0, 1));
  1422. });
  1423. if (relPos === 'cr') {
  1424. panel.classes.toggle('arrow-left', true);
  1425. panel.classes.toggle('arrow-right', false);
  1426. } else if (relPos === 'cl') {
  1427. panel.classes.toggle('arrow-left', true);
  1428. panel.classes.toggle('arrow-right', true);
  1429. } else {
  1430. Tools.each({
  1431. l: 'left',
  1432. r: 'right'
  1433. }, function (cls, pos) {
  1434. panel.classes.toggle('arrow-' + cls, pos === relPos.substr(1, 1));
  1435. });
  1436. }
  1437. };
  1438. var showToolbar = function (panel, id) {
  1439. var toolbars = panel.items().filter('#' + id);
  1440. if (toolbars.length > 0) {
  1441. toolbars[0].show();
  1442. panel.reflow();
  1443. return true;
  1444. }
  1445. return false;
  1446. };
  1447. var repositionPanelAt = function (panel, id, editor, targetRect) {
  1448. var contentAreaRect, panelRect, result, userConstainHandler;
  1449. userConstainHandler = EditorSettings.getHandlerOr(editor, 'inline_toolbar_position_handler', Layout.defaultHandler);
  1450. contentAreaRect = Measure.getContentAreaRect(editor);
  1451. panelRect = DOMUtils.DOM.getRect(panel.getEl());
  1452. if (id === 'insert') {
  1453. result = Layout.calcInsert(targetRect, contentAreaRect, panelRect);
  1454. } else {
  1455. result = Layout.calc(targetRect, contentAreaRect, panelRect);
  1456. }
  1457. if (result) {
  1458. panelRect = result.rect;
  1459. currentRect = targetRect;
  1460. movePanelTo(panel, Layout.userConstrain(userConstainHandler, targetRect, contentAreaRect, panelRect));
  1461. togglePositionClass(panel, result.position);
  1462. return true;
  1463. } else {
  1464. return false;
  1465. }
  1466. };
  1467. var showPanelAt = function (panel, id, editor, targetRect) {
  1468. showPanel(panel);
  1469. panel.items().hide();
  1470. if (!showToolbar(panel, id)) {
  1471. hide(panel);
  1472. return;
  1473. }
  1474. if (repositionPanelAt(panel, id, editor, targetRect) === false) {
  1475. hide(panel);
  1476. }
  1477. };
  1478. var hasFormVisible = function () {
  1479. return panel.items().filter('form:visible').length > 0;
  1480. };
  1481. var showForm = function (editor, id) {
  1482. if (panel) {
  1483. panel.items().hide();
  1484. if (!showToolbar(panel, id)) {
  1485. hide(panel);
  1486. return;
  1487. }
  1488. var contentAreaRect, panelRect, result, userConstainHandler;
  1489. showPanel(panel);
  1490. panel.items().hide();
  1491. showToolbar(panel, id);
  1492. userConstainHandler = EditorSettings.getHandlerOr(editor, 'inline_toolbar_position_handler', Layout.defaultHandler);
  1493. contentAreaRect = Measure.getContentAreaRect(editor);
  1494. panelRect = DOMUtils.DOM.getRect(panel.getEl());
  1495. result = Layout.calc(currentRect, contentAreaRect, panelRect);
  1496. if (result) {
  1497. panelRect = result.rect;
  1498. movePanelTo(panel, Layout.userConstrain(userConstainHandler, currentRect, contentAreaRect, panelRect));
  1499. togglePositionClass(panel, result.position);
  1500. }
  1501. }
  1502. };
  1503. var show = function (editor, id, targetRect, toolbars) {
  1504. if (!panel) {
  1505. panel = create(editor, toolbars);
  1506. panel.renderTo(document.body).reflow().moveTo(targetRect.x, targetRect.y);
  1507. editor.nodeChanged();
  1508. }
  1509. showPanelAt(panel, id, editor, targetRect);
  1510. };
  1511. var reposition = function (editor, id, targetRect) {
  1512. if (panel) {
  1513. repositionPanelAt(panel, id, editor, targetRect);
  1514. }
  1515. };
  1516. var hide = function () {
  1517. if (panel) {
  1518. panel.hide();
  1519. }
  1520. };
  1521. var focus = function () {
  1522. if (panel) {
  1523. panel.find('toolbar:visible').eq(0).each(function (item) {
  1524. item.focus(true);
  1525. });
  1526. }
  1527. };
  1528. var remove = function () {
  1529. if (panel) {
  1530. panel.remove();
  1531. panel = null;
  1532. }
  1533. };
  1534. var inForm = function () {
  1535. return panel && panel.visible() && hasFormVisible();
  1536. };
  1537. return {
  1538. show: show,
  1539. showForm: showForm,
  1540. reposition: reposition,
  1541. inForm: inForm,
  1542. hide: hide,
  1543. focus: focus,
  1544. remove: remove
  1545. };
  1546. };
  1547. }
  1548. );
  1549. /**
  1550. * Conversions.js
  1551. *
  1552. * Released under LGPL License.
  1553. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1554. *
  1555. * License: http://www.tinymce.com/license
  1556. * Contributing: http://www.tinymce.com/contributing
  1557. */
  1558. define(
  1559. 'tinymce.themes.inlite.file.Conversions',
  1560. [
  1561. 'tinymce.core.util.Promise'
  1562. ],
  1563. function (Promise) {
  1564. var blobToBase64 = function (blob) {
  1565. return new Promise(function (resolve) {
  1566. var reader = new FileReader();
  1567. reader.onloadend = function () {
  1568. resolve(reader.result.split(',')[1]);
  1569. };
  1570. reader.readAsDataURL(blob);
  1571. });
  1572. };
  1573. return {
  1574. blobToBase64: blobToBase64
  1575. };
  1576. }
  1577. );
  1578. /**
  1579. * Picker.js
  1580. *
  1581. * Released under LGPL License.
  1582. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1583. *
  1584. * License: http://www.tinymce.com/license
  1585. * Contributing: http://www.tinymce.com/contributing
  1586. */
  1587. define(
  1588. 'tinymce.themes.inlite.file.Picker',
  1589. [
  1590. 'tinymce.core.util.Promise'
  1591. ],
  1592. function (Promise) {
  1593. var pickFile = function () {
  1594. return new Promise(function (resolve) {
  1595. var fileInput;
  1596. fileInput = document.createElement("input");
  1597. fileInput.type = "file";
  1598. fileInput.style.position = 'fixed';
  1599. fileInput.style.left = 0;
  1600. fileInput.style.top = 0;
  1601. fileInput.style.opacity = 0.001;
  1602. document.body.appendChild(fileInput);
  1603. fileInput.onchange = function (e) {
  1604. resolve(Array.prototype.slice.call(e.target.files));
  1605. };
  1606. fileInput.click();
  1607. fileInput.parentNode.removeChild(fileInput);
  1608. });
  1609. };
  1610. return {
  1611. pickFile: pickFile
  1612. };
  1613. }
  1614. );
  1615. /**
  1616. * Buttons.js
  1617. *
  1618. * Released under LGPL License.
  1619. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1620. *
  1621. * License: http://www.tinymce.com/license
  1622. * Contributing: http://www.tinymce.com/contributing
  1623. */
  1624. define(
  1625. 'tinymce.themes.inlite.ui.Buttons',
  1626. [
  1627. 'tinymce.themes.inlite.ui.Panel',
  1628. 'tinymce.themes.inlite.file.Conversions',
  1629. 'tinymce.themes.inlite.file.Picker',
  1630. 'tinymce.themes.inlite.core.Actions'
  1631. ],
  1632. function (Panel, Conversions, Picker, Actions) {
  1633. var addHeaderButtons = function (editor) {
  1634. var formatBlock = function (name) {
  1635. return function () {
  1636. Actions.formatBlock(editor, name);
  1637. };
  1638. };
  1639. for (var i = 1; i < 6; i++) {
  1640. var name = 'h' + i;
  1641. editor.addButton(name, {
  1642. text: name.toUpperCase(),
  1643. tooltip: 'Heading ' + i,
  1644. stateSelector: name,
  1645. onclick: formatBlock(name),
  1646. onPostRender: function () {
  1647. // TODO: Remove this hack that produces bold H1-H6 when we have proper icons
  1648. var span = this.getEl().firstChild.firstChild;
  1649. span.style.fontWeight = 'bold';
  1650. }
  1651. });
  1652. }
  1653. };
  1654. var addToEditor = function (editor, panel) {
  1655. editor.addButton('quicklink', {
  1656. icon: 'link',
  1657. tooltip: 'Insert/Edit link',
  1658. stateSelector: 'a[href]',
  1659. onclick: function () {
  1660. panel.showForm(editor, 'quicklink');
  1661. }
  1662. });
  1663. editor.addButton('quickimage', {
  1664. icon: 'image',
  1665. tooltip: 'Insert image',
  1666. onclick: function () {
  1667. Picker.pickFile().then(function (files) {
  1668. var blob = files[0];
  1669. Conversions.blobToBase64(blob).then(function (base64) {
  1670. Actions.insertBlob(editor, base64, blob);
  1671. });
  1672. });
  1673. }
  1674. });
  1675. editor.addButton('quicktable', {
  1676. icon: 'table',
  1677. tooltip: 'Insert table',
  1678. onclick: function () {
  1679. panel.hide();
  1680. Actions.insertTable(editor, 2, 2);
  1681. }
  1682. });
  1683. addHeaderButtons(editor);
  1684. };
  1685. return {
  1686. addToEditor: addToEditor
  1687. };
  1688. }
  1689. );
  1690. /**
  1691. * Theme.js
  1692. *
  1693. * Released under LGPL License.
  1694. * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
  1695. *
  1696. * License: http://www.tinymce.com/license
  1697. * Contributing: http://www.tinymce.com/contributing
  1698. */
  1699. define(
  1700. 'tinymce.themes.inlite.Theme',
  1701. [
  1702. 'tinymce.core.ThemeManager',
  1703. 'tinymce.core.ui.Api',
  1704. 'tinymce.core.util.Delay',
  1705. 'tinymce.themes.inlite.alien.Arr',
  1706. 'tinymce.themes.inlite.alien.EditorSettings',
  1707. 'tinymce.themes.inlite.core.ElementMatcher',
  1708. 'tinymce.themes.inlite.core.Matcher',
  1709. 'tinymce.themes.inlite.core.PredicateId',
  1710. 'tinymce.themes.inlite.core.SelectionMatcher',
  1711. 'tinymce.themes.inlite.core.SkinLoader',
  1712. 'tinymce.themes.inlite.ui.Buttons',
  1713. 'tinymce.themes.inlite.ui.Panel'
  1714. ],
  1715. function (
  1716. ThemeManager, Api, Delay, Arr, EditorSettings, ElementMatcher, Matcher,
  1717. PredicateId, SelectionMatcher, SkinLoader, Buttons, Panel
  1718. ) {
  1719. var getSelectionElements = function (editor) {
  1720. var node = editor.selection.getNode();
  1721. var elms = editor.dom.getParents(node);
  1722. return elms;
  1723. };
  1724. var createToolbar = function (editor, selector, id, items) {
  1725. var selectorPredicate = function (elm) {
  1726. return editor.dom.is(elm, selector);
  1727. };
  1728. return {
  1729. predicate: selectorPredicate,
  1730. id: id,
  1731. items: items
  1732. };
  1733. };
  1734. var getToolbars = function (editor) {
  1735. var contextToolbars = editor.contextToolbars;
  1736. return Arr.flatten([
  1737. contextToolbars ? contextToolbars : [],
  1738. createToolbar(editor, 'img', 'image', 'alignleft aligncenter alignright')
  1739. ]);
  1740. };
  1741. var findMatchResult = function (editor, toolbars) {
  1742. var result, elements, contextToolbarsPredicateIds;
  1743. elements = getSelectionElements(editor);
  1744. contextToolbarsPredicateIds = PredicateId.fromContextToolbars(toolbars);
  1745. result = Matcher.match(editor, [
  1746. ElementMatcher.element(elements[0], contextToolbarsPredicateIds),
  1747. SelectionMatcher.textSelection('text'),
  1748. SelectionMatcher.emptyTextBlock(elements, 'insert'),
  1749. ElementMatcher.parent(elements, contextToolbarsPredicateIds)
  1750. ]);
  1751. return result && result.rect ? result : null;
  1752. };
  1753. var togglePanel = function (editor, panel) {
  1754. var toggle = function () {
  1755. var toolbars = getToolbars(editor);
  1756. var result = findMatchResult(editor, toolbars);
  1757. if (result) {
  1758. panel.show(editor, result.id, result.rect, toolbars);
  1759. } else {
  1760. panel.hide();
  1761. }
  1762. };
  1763. return function () {
  1764. if (!editor.removed) {
  1765. toggle();
  1766. }
  1767. };
  1768. };
  1769. var repositionPanel = function (editor, panel) {
  1770. return function () {
  1771. var toolbars = getToolbars(editor);
  1772. var result = findMatchResult(editor, toolbars);
  1773. if (result) {
  1774. panel.reposition(editor, result.id, result.rect);
  1775. }
  1776. };
  1777. };
  1778. var ignoreWhenFormIsVisible = function (editor, panel, f) {
  1779. return function () {
  1780. if (!editor.removed && !panel.inForm()) {
  1781. f();
  1782. }
  1783. };
  1784. };
  1785. var bindContextualToolbarsEvents = function (editor, panel) {
  1786. var throttledTogglePanel = Delay.throttle(togglePanel(editor, panel), 0);
  1787. var throttledTogglePanelWhenNotInForm = Delay.throttle(ignoreWhenFormIsVisible(editor, panel, togglePanel(editor, panel)), 0);
  1788. editor.on('blur hide ObjectResizeStart', panel.hide);
  1789. editor.on('click', throttledTogglePanel);
  1790. editor.on('nodeChange mouseup', throttledTogglePanelWhenNotInForm);
  1791. editor.on('ResizeEditor keyup', throttledTogglePanel);
  1792. editor.on('ResizeWindow', repositionPanel(editor, panel));
  1793. editor.on('remove', panel.remove);
  1794. editor.shortcuts.add('Alt+F10', '', panel.focus);
  1795. };
  1796. var overrideLinkShortcut = function (editor, panel) {
  1797. editor.shortcuts.remove('meta+k');
  1798. editor.shortcuts.add('meta+k', '', function () {
  1799. var toolbars = getToolbars(editor);
  1800. var result = result = Matcher.match(editor, [
  1801. SelectionMatcher.textSelection('quicklink')
  1802. ]);
  1803. if (result) {
  1804. panel.show(editor, result.id, result.rect, toolbars);
  1805. }
  1806. });
  1807. };
  1808. var renderInlineUI = function (editor, panel) {
  1809. SkinLoader.load(editor, function () {
  1810. bindContextualToolbarsEvents(editor, panel);
  1811. overrideLinkShortcut(editor, panel);
  1812. });
  1813. return {};
  1814. };
  1815. var fail = function (message) {
  1816. throw new Error(message);
  1817. };
  1818. ThemeManager.add('inlite', function (editor) {
  1819. var panel = new Panel();
  1820. Buttons.addToEditor(editor, panel);
  1821. var renderUI = function () {
  1822. return editor.inline ? renderInlineUI(editor, panel) : fail('inlite theme only supports inline mode.');
  1823. };
  1824. return {
  1825. renderUI: renderUI
  1826. };
  1827. });
  1828. Api.appendTo(window.tinymce ? window.tinymce : {});
  1829. return function () { };
  1830. }
  1831. );
  1832. dem('tinymce.themes.inlite.Theme')();
  1833. })();