plugin.js 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. /**
  2. * TinyMCE version 6.0.3 (2022-05-25)
  3. */
  4. (function () {
  5. 'use strict';
  6. const Cell = initial => {
  7. let value = initial;
  8. const get = () => {
  9. return value;
  10. };
  11. const set = v => {
  12. value = v;
  13. };
  14. return {
  15. get,
  16. set
  17. };
  18. };
  19. var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  20. const get$5 = fullscreenState => ({ isFullscreen: () => fullscreenState.get() !== null });
  21. const hasProto = (v, constructor, predicate) => {
  22. var _a;
  23. if (predicate(v, constructor.prototype)) {
  24. return true;
  25. } else {
  26. return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
  27. }
  28. };
  29. const typeOf = x => {
  30. const t = typeof x;
  31. if (x === null) {
  32. return 'null';
  33. } else if (t === 'object' && Array.isArray(x)) {
  34. return 'array';
  35. } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
  36. return 'string';
  37. } else {
  38. return t;
  39. }
  40. };
  41. const isType$1 = type => value => typeOf(value) === type;
  42. const isSimpleType = type => value => typeof value === type;
  43. const eq$1 = t => a => t === a;
  44. const isString = isType$1('string');
  45. const isArray = isType$1('array');
  46. const isNull = eq$1(null);
  47. const isBoolean = isSimpleType('boolean');
  48. const isNullable = a => a === null || a === undefined;
  49. const isNonNullable = a => !isNullable(a);
  50. const isFunction = isSimpleType('function');
  51. const isNumber = isSimpleType('number');
  52. const noop = () => {
  53. };
  54. const compose = (fa, fb) => {
  55. return (...args) => {
  56. return fa(fb.apply(null, args));
  57. };
  58. };
  59. const compose1 = (fbc, fab) => a => fbc(fab(a));
  60. const constant = value => {
  61. return () => {
  62. return value;
  63. };
  64. };
  65. function curry(fn, ...initialArgs) {
  66. return (...restArgs) => {
  67. const all = initialArgs.concat(restArgs);
  68. return fn.apply(null, all);
  69. };
  70. }
  71. const never = constant(false);
  72. const always = constant(true);
  73. class Optional {
  74. constructor(tag, value) {
  75. this.tag = tag;
  76. this.value = value;
  77. }
  78. static some(value) {
  79. return new Optional(true, value);
  80. }
  81. static none() {
  82. return Optional.singletonNone;
  83. }
  84. fold(onNone, onSome) {
  85. if (this.tag) {
  86. return onSome(this.value);
  87. } else {
  88. return onNone();
  89. }
  90. }
  91. isSome() {
  92. return this.tag;
  93. }
  94. isNone() {
  95. return !this.tag;
  96. }
  97. map(mapper) {
  98. if (this.tag) {
  99. return Optional.some(mapper(this.value));
  100. } else {
  101. return Optional.none();
  102. }
  103. }
  104. bind(binder) {
  105. if (this.tag) {
  106. return binder(this.value);
  107. } else {
  108. return Optional.none();
  109. }
  110. }
  111. exists(predicate) {
  112. return this.tag && predicate(this.value);
  113. }
  114. forall(predicate) {
  115. return !this.tag || predicate(this.value);
  116. }
  117. filter(predicate) {
  118. if (!this.tag || predicate(this.value)) {
  119. return this;
  120. } else {
  121. return Optional.none();
  122. }
  123. }
  124. getOr(replacement) {
  125. return this.tag ? this.value : replacement;
  126. }
  127. or(replacement) {
  128. return this.tag ? this : replacement;
  129. }
  130. getOrThunk(thunk) {
  131. return this.tag ? this.value : thunk();
  132. }
  133. orThunk(thunk) {
  134. return this.tag ? this : thunk();
  135. }
  136. getOrDie(message) {
  137. if (!this.tag) {
  138. throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
  139. } else {
  140. return this.value;
  141. }
  142. }
  143. static from(value) {
  144. return isNonNullable(value) ? Optional.some(value) : Optional.none();
  145. }
  146. getOrNull() {
  147. return this.tag ? this.value : null;
  148. }
  149. getOrUndefined() {
  150. return this.value;
  151. }
  152. each(worker) {
  153. if (this.tag) {
  154. worker(this.value);
  155. }
  156. }
  157. toArray() {
  158. return this.tag ? [this.value] : [];
  159. }
  160. toString() {
  161. return this.tag ? `some(${ this.value })` : 'none()';
  162. }
  163. }
  164. Optional.singletonNone = new Optional(false);
  165. const singleton = doRevoke => {
  166. const subject = Cell(Optional.none());
  167. const revoke = () => subject.get().each(doRevoke);
  168. const clear = () => {
  169. revoke();
  170. subject.set(Optional.none());
  171. };
  172. const isSet = () => subject.get().isSome();
  173. const get = () => subject.get();
  174. const set = s => {
  175. revoke();
  176. subject.set(Optional.some(s));
  177. };
  178. return {
  179. clear,
  180. isSet,
  181. get,
  182. set
  183. };
  184. };
  185. const unbindable = () => singleton(s => s.unbind());
  186. const value = () => {
  187. const subject = singleton(noop);
  188. const on = f => subject.get().each(f);
  189. return {
  190. ...subject,
  191. on
  192. };
  193. };
  194. const first = (fn, rate) => {
  195. let timer = null;
  196. const cancel = () => {
  197. if (!isNull(timer)) {
  198. clearTimeout(timer);
  199. timer = null;
  200. }
  201. };
  202. const throttle = (...args) => {
  203. if (isNull(timer)) {
  204. timer = setTimeout(() => {
  205. timer = null;
  206. fn.apply(null, args);
  207. }, rate);
  208. }
  209. };
  210. return {
  211. cancel,
  212. throttle
  213. };
  214. };
  215. const nativePush = Array.prototype.push;
  216. const map = (xs, f) => {
  217. const len = xs.length;
  218. const r = new Array(len);
  219. for (let i = 0; i < len; i++) {
  220. const x = xs[i];
  221. r[i] = f(x, i);
  222. }
  223. return r;
  224. };
  225. const each$1 = (xs, f) => {
  226. for (let i = 0, len = xs.length; i < len; i++) {
  227. const x = xs[i];
  228. f(x, i);
  229. }
  230. };
  231. const filter$1 = (xs, pred) => {
  232. const r = [];
  233. for (let i = 0, len = xs.length; i < len; i++) {
  234. const x = xs[i];
  235. if (pred(x, i)) {
  236. r.push(x);
  237. }
  238. }
  239. return r;
  240. };
  241. const findUntil = (xs, pred, until) => {
  242. for (let i = 0, len = xs.length; i < len; i++) {
  243. const x = xs[i];
  244. if (pred(x, i)) {
  245. return Optional.some(x);
  246. } else if (until(x, i)) {
  247. break;
  248. }
  249. }
  250. return Optional.none();
  251. };
  252. const find$1 = (xs, pred) => {
  253. return findUntil(xs, pred, never);
  254. };
  255. const flatten = xs => {
  256. const r = [];
  257. for (let i = 0, len = xs.length; i < len; ++i) {
  258. if (!isArray(xs[i])) {
  259. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  260. }
  261. nativePush.apply(r, xs[i]);
  262. }
  263. return r;
  264. };
  265. const bind$3 = (xs, f) => flatten(map(xs, f));
  266. const get$4 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  267. const head = xs => get$4(xs, 0);
  268. const findMap = (arr, f) => {
  269. for (let i = 0; i < arr.length; i++) {
  270. const r = f(arr[i], i);
  271. if (r.isSome()) {
  272. return r;
  273. }
  274. }
  275. return Optional.none();
  276. };
  277. const keys = Object.keys;
  278. const each = (obj, f) => {
  279. const props = keys(obj);
  280. for (let k = 0, len = props.length; k < len; k++) {
  281. const i = props[k];
  282. const x = obj[i];
  283. f(x, i);
  284. }
  285. };
  286. const contains = (str, substr) => {
  287. return str.indexOf(substr) !== -1;
  288. };
  289. const isSupported$1 = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
  290. const fromHtml = (html, scope) => {
  291. const doc = scope || document;
  292. const div = doc.createElement('div');
  293. div.innerHTML = html;
  294. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  295. const message = 'HTML does not have a single root node';
  296. console.error(message, html);
  297. throw new Error(message);
  298. }
  299. return fromDom(div.childNodes[0]);
  300. };
  301. const fromTag = (tag, scope) => {
  302. const doc = scope || document;
  303. const node = doc.createElement(tag);
  304. return fromDom(node);
  305. };
  306. const fromText = (text, scope) => {
  307. const doc = scope || document;
  308. const node = doc.createTextNode(text);
  309. return fromDom(node);
  310. };
  311. const fromDom = node => {
  312. if (node === null || node === undefined) {
  313. throw new Error('Node cannot be null or undefined');
  314. }
  315. return { dom: node };
  316. };
  317. const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  318. const SugarElement = {
  319. fromHtml,
  320. fromTag,
  321. fromText,
  322. fromDom,
  323. fromPoint
  324. };
  325. typeof window !== 'undefined' ? window : Function('return this;')();
  326. const DOCUMENT = 9;
  327. const DOCUMENT_FRAGMENT = 11;
  328. const ELEMENT = 1;
  329. const TEXT = 3;
  330. const type = element => element.dom.nodeType;
  331. const isType = t => element => type(element) === t;
  332. const isElement = isType(ELEMENT);
  333. const isText = isType(TEXT);
  334. const isDocument = isType(DOCUMENT);
  335. const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  336. const is = (element, selector) => {
  337. const dom = element.dom;
  338. if (dom.nodeType !== ELEMENT) {
  339. return false;
  340. } else {
  341. const elem = dom;
  342. if (elem.matches !== undefined) {
  343. return elem.matches(selector);
  344. } else if (elem.msMatchesSelector !== undefined) {
  345. return elem.msMatchesSelector(selector);
  346. } else if (elem.webkitMatchesSelector !== undefined) {
  347. return elem.webkitMatchesSelector(selector);
  348. } else if (elem.mozMatchesSelector !== undefined) {
  349. return elem.mozMatchesSelector(selector);
  350. } else {
  351. throw new Error('Browser lacks native selectors');
  352. }
  353. }
  354. };
  355. const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  356. const all$1 = (selector, scope) => {
  357. const base = scope === undefined ? document : scope.dom;
  358. return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
  359. };
  360. const eq = (e1, e2) => e1.dom === e2.dom;
  361. const owner = element => SugarElement.fromDom(element.dom.ownerDocument);
  362. const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos);
  363. const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  364. const parents = (element, isRoot) => {
  365. const stop = isFunction(isRoot) ? isRoot : never;
  366. let dom = element.dom;
  367. const ret = [];
  368. while (dom.parentNode !== null && dom.parentNode !== undefined) {
  369. const rawParent = dom.parentNode;
  370. const p = SugarElement.fromDom(rawParent);
  371. ret.push(p);
  372. if (stop(p) === true) {
  373. break;
  374. } else {
  375. dom = rawParent;
  376. }
  377. }
  378. return ret;
  379. };
  380. const siblings$2 = element => {
  381. const filterSelf = elements => filter$1(elements, x => !eq(element, x));
  382. return parent(element).map(children).map(filterSelf).getOr([]);
  383. };
  384. const children = element => map(element.dom.childNodes, SugarElement.fromDom);
  385. const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  386. const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  387. const isSupported = constant(supported);
  388. const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  389. const getShadowRoot = e => {
  390. const r = getRootNode(e);
  391. return isShadowRoot(r) ? Optional.some(r) : Optional.none();
  392. };
  393. const getShadowHost = e => SugarElement.fromDom(e.dom.host);
  394. const getOriginalEventTarget = event => {
  395. if (isSupported() && isNonNullable(event.target)) {
  396. const el = SugarElement.fromDom(event.target);
  397. if (isElement(el) && isOpenShadowHost(el)) {
  398. if (event.composed && event.composedPath) {
  399. const composedPath = event.composedPath();
  400. if (composedPath) {
  401. return head(composedPath);
  402. }
  403. }
  404. }
  405. }
  406. return Optional.from(event.target);
  407. };
  408. const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
  409. const inBody = element => {
  410. const dom = isText(element) ? element.dom.parentNode : element.dom;
  411. if (dom === undefined || dom === null || dom.ownerDocument === null) {
  412. return false;
  413. }
  414. const doc = dom.ownerDocument;
  415. return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  416. };
  417. const getBody = doc => {
  418. const b = doc.dom.body;
  419. if (b === null || b === undefined) {
  420. throw new Error('Body is not available yet');
  421. }
  422. return SugarElement.fromDom(b);
  423. };
  424. const rawSet = (dom, key, value) => {
  425. if (isString(value) || isBoolean(value) || isNumber(value)) {
  426. dom.setAttribute(key, value + '');
  427. } else {
  428. console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
  429. throw new Error('Attribute value was not simple');
  430. }
  431. };
  432. const set = (element, key, value) => {
  433. rawSet(element.dom, key, value);
  434. };
  435. const get$3 = (element, key) => {
  436. const v = element.dom.getAttribute(key);
  437. return v === null ? undefined : v;
  438. };
  439. const remove = (element, key) => {
  440. element.dom.removeAttribute(key);
  441. };
  442. const internalSet = (dom, property, value) => {
  443. if (!isString(value)) {
  444. console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
  445. throw new Error('CSS value must be a string: ' + value);
  446. }
  447. if (isSupported$1(dom)) {
  448. dom.style.setProperty(property, value);
  449. }
  450. };
  451. const setAll = (element, css) => {
  452. const dom = element.dom;
  453. each(css, (v, k) => {
  454. internalSet(dom, k, v);
  455. });
  456. };
  457. const get$2 = (element, property) => {
  458. const dom = element.dom;
  459. const styles = window.getComputedStyle(dom);
  460. const r = styles.getPropertyValue(property);
  461. return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
  462. };
  463. const getUnsafeProperty = (dom, property) => isSupported$1(dom) ? dom.style.getPropertyValue(property) : '';
  464. const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
  465. target,
  466. x,
  467. y,
  468. stop,
  469. prevent,
  470. kill,
  471. raw
  472. });
  473. const fromRawEvent = rawEvent => {
  474. const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
  475. const stop = () => rawEvent.stopPropagation();
  476. const prevent = () => rawEvent.preventDefault();
  477. const kill = compose(prevent, stop);
  478. return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
  479. };
  480. const handle = (filter, handler) => rawEvent => {
  481. if (filter(rawEvent)) {
  482. handler(fromRawEvent(rawEvent));
  483. }
  484. };
  485. const binder = (element, event, filter, handler, useCapture) => {
  486. const wrapped = handle(filter, handler);
  487. element.dom.addEventListener(event, wrapped, useCapture);
  488. return { unbind: curry(unbind, element, event, wrapped, useCapture) };
  489. };
  490. const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
  491. const unbind = (element, event, handler, useCapture) => {
  492. element.dom.removeEventListener(event, handler, useCapture);
  493. };
  494. const filter = always;
  495. const bind$1 = (element, event, handler) => bind$2(element, event, filter, handler);
  496. const cached = f => {
  497. let called = false;
  498. let r;
  499. return (...args) => {
  500. if (!called) {
  501. called = true;
  502. r = f.apply(null, args);
  503. }
  504. return r;
  505. };
  506. };
  507. const DeviceType = (os, browser, userAgent, mediaMatch) => {
  508. const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
  509. const isiPhone = os.isiOS() && !isiPad;
  510. const isMobile = os.isiOS() || os.isAndroid();
  511. const isTouch = isMobile || mediaMatch('(pointer:coarse)');
  512. const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
  513. const isPhone = isiPhone || isMobile && !isTablet;
  514. const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
  515. const isDesktop = !isPhone && !isTablet && !iOSwebview;
  516. return {
  517. isiPad: constant(isiPad),
  518. isiPhone: constant(isiPhone),
  519. isTablet: constant(isTablet),
  520. isPhone: constant(isPhone),
  521. isTouch: constant(isTouch),
  522. isAndroid: os.isAndroid,
  523. isiOS: os.isiOS,
  524. isWebView: constant(iOSwebview),
  525. isDesktop: constant(isDesktop)
  526. };
  527. };
  528. const firstMatch = (regexes, s) => {
  529. for (let i = 0; i < regexes.length; i++) {
  530. const x = regexes[i];
  531. if (x.test(s)) {
  532. return x;
  533. }
  534. }
  535. return undefined;
  536. };
  537. const find = (regexes, agent) => {
  538. const r = firstMatch(regexes, agent);
  539. if (!r) {
  540. return {
  541. major: 0,
  542. minor: 0
  543. };
  544. }
  545. const group = i => {
  546. return Number(agent.replace(r, '$' + i));
  547. };
  548. return nu$2(group(1), group(2));
  549. };
  550. const detect$3 = (versionRegexes, agent) => {
  551. const cleanedAgent = String(agent).toLowerCase();
  552. if (versionRegexes.length === 0) {
  553. return unknown$2();
  554. }
  555. return find(versionRegexes, cleanedAgent);
  556. };
  557. const unknown$2 = () => {
  558. return nu$2(0, 0);
  559. };
  560. const nu$2 = (major, minor) => {
  561. return {
  562. major,
  563. minor
  564. };
  565. };
  566. const Version = {
  567. nu: nu$2,
  568. detect: detect$3,
  569. unknown: unknown$2
  570. };
  571. const detectBrowser$1 = (browsers, userAgentData) => {
  572. return findMap(userAgentData.brands, uaBrand => {
  573. const lcBrand = uaBrand.brand.toLowerCase();
  574. return find$1(browsers, browser => {
  575. var _a;
  576. return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
  577. }).map(info => ({
  578. current: info.name,
  579. version: Version.nu(parseInt(uaBrand.version, 10), 0)
  580. }));
  581. });
  582. };
  583. const detect$2 = (candidates, userAgent) => {
  584. const agent = String(userAgent).toLowerCase();
  585. return find$1(candidates, candidate => {
  586. return candidate.search(agent);
  587. });
  588. };
  589. const detectBrowser = (browsers, userAgent) => {
  590. return detect$2(browsers, userAgent).map(browser => {
  591. const version = Version.detect(browser.versionRegexes, userAgent);
  592. return {
  593. current: browser.name,
  594. version
  595. };
  596. });
  597. };
  598. const detectOs = (oses, userAgent) => {
  599. return detect$2(oses, userAgent).map(os => {
  600. const version = Version.detect(os.versionRegexes, userAgent);
  601. return {
  602. current: os.name,
  603. version
  604. };
  605. });
  606. };
  607. const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  608. const checkContains = target => {
  609. return uastring => {
  610. return contains(uastring, target);
  611. };
  612. };
  613. const browsers = [
  614. {
  615. name: 'Edge',
  616. versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
  617. search: uastring => {
  618. return contains(uastring, 'edge/') && contains(uastring, 'chrome') && contains(uastring, 'safari') && contains(uastring, 'applewebkit');
  619. }
  620. },
  621. {
  622. name: 'Chromium',
  623. brand: 'Chromium',
  624. versionRegexes: [
  625. /.*?chrome\/([0-9]+)\.([0-9]+).*/,
  626. normalVersionRegex
  627. ],
  628. search: uastring => {
  629. return contains(uastring, 'chrome') && !contains(uastring, 'chromeframe');
  630. }
  631. },
  632. {
  633. name: 'IE',
  634. versionRegexes: [
  635. /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
  636. /.*?rv:([0-9]+)\.([0-9]+).*/
  637. ],
  638. search: uastring => {
  639. return contains(uastring, 'msie') || contains(uastring, 'trident');
  640. }
  641. },
  642. {
  643. name: 'Opera',
  644. versionRegexes: [
  645. normalVersionRegex,
  646. /.*?opera\/([0-9]+)\.([0-9]+).*/
  647. ],
  648. search: checkContains('opera')
  649. },
  650. {
  651. name: 'Firefox',
  652. versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
  653. search: checkContains('firefox')
  654. },
  655. {
  656. name: 'Safari',
  657. versionRegexes: [
  658. normalVersionRegex,
  659. /.*?cpu os ([0-9]+)_([0-9]+).*/
  660. ],
  661. search: uastring => {
  662. return (contains(uastring, 'safari') || contains(uastring, 'mobile/')) && contains(uastring, 'applewebkit');
  663. }
  664. }
  665. ];
  666. const oses = [
  667. {
  668. name: 'Windows',
  669. search: checkContains('win'),
  670. versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
  671. },
  672. {
  673. name: 'iOS',
  674. search: uastring => {
  675. return contains(uastring, 'iphone') || contains(uastring, 'ipad');
  676. },
  677. versionRegexes: [
  678. /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
  679. /.*cpu os ([0-9]+)_([0-9]+).*/,
  680. /.*cpu iphone os ([0-9]+)_([0-9]+).*/
  681. ]
  682. },
  683. {
  684. name: 'Android',
  685. search: checkContains('android'),
  686. versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
  687. },
  688. {
  689. name: 'macOS',
  690. search: checkContains('mac os x'),
  691. versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
  692. },
  693. {
  694. name: 'Linux',
  695. search: checkContains('linux'),
  696. versionRegexes: []
  697. },
  698. {
  699. name: 'Solaris',
  700. search: checkContains('sunos'),
  701. versionRegexes: []
  702. },
  703. {
  704. name: 'FreeBSD',
  705. search: checkContains('freebsd'),
  706. versionRegexes: []
  707. },
  708. {
  709. name: 'ChromeOS',
  710. search: checkContains('cros'),
  711. versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
  712. }
  713. ];
  714. const PlatformInfo = {
  715. browsers: constant(browsers),
  716. oses: constant(oses)
  717. };
  718. const edge = 'Edge';
  719. const chromium = 'Chromium';
  720. const ie = 'IE';
  721. const opera = 'Opera';
  722. const firefox = 'Firefox';
  723. const safari = 'Safari';
  724. const unknown$1 = () => {
  725. return nu$1({
  726. current: undefined,
  727. version: Version.unknown()
  728. });
  729. };
  730. const nu$1 = info => {
  731. const current = info.current;
  732. const version = info.version;
  733. const isBrowser = name => () => current === name;
  734. return {
  735. current,
  736. version,
  737. isEdge: isBrowser(edge),
  738. isChromium: isBrowser(chromium),
  739. isIE: isBrowser(ie),
  740. isOpera: isBrowser(opera),
  741. isFirefox: isBrowser(firefox),
  742. isSafari: isBrowser(safari)
  743. };
  744. };
  745. const Browser = {
  746. unknown: unknown$1,
  747. nu: nu$1,
  748. edge: constant(edge),
  749. chromium: constant(chromium),
  750. ie: constant(ie),
  751. opera: constant(opera),
  752. firefox: constant(firefox),
  753. safari: constant(safari)
  754. };
  755. const windows = 'Windows';
  756. const ios = 'iOS';
  757. const android = 'Android';
  758. const linux = 'Linux';
  759. const macos = 'macOS';
  760. const solaris = 'Solaris';
  761. const freebsd = 'FreeBSD';
  762. const chromeos = 'ChromeOS';
  763. const unknown = () => {
  764. return nu({
  765. current: undefined,
  766. version: Version.unknown()
  767. });
  768. };
  769. const nu = info => {
  770. const current = info.current;
  771. const version = info.version;
  772. const isOS = name => () => current === name;
  773. return {
  774. current,
  775. version,
  776. isWindows: isOS(windows),
  777. isiOS: isOS(ios),
  778. isAndroid: isOS(android),
  779. isMacOS: isOS(macos),
  780. isLinux: isOS(linux),
  781. isSolaris: isOS(solaris),
  782. isFreeBSD: isOS(freebsd),
  783. isChromeOS: isOS(chromeos)
  784. };
  785. };
  786. const OperatingSystem = {
  787. unknown,
  788. nu,
  789. windows: constant(windows),
  790. ios: constant(ios),
  791. android: constant(android),
  792. linux: constant(linux),
  793. macos: constant(macos),
  794. solaris: constant(solaris),
  795. freebsd: constant(freebsd),
  796. chromeos: constant(chromeos)
  797. };
  798. const detect$1 = (userAgent, userAgentDataOpt, mediaMatch) => {
  799. const browsers = PlatformInfo.browsers();
  800. const oses = PlatformInfo.oses();
  801. const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
  802. const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
  803. const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
  804. return {
  805. browser,
  806. os,
  807. deviceType
  808. };
  809. };
  810. const PlatformDetection = { detect: detect$1 };
  811. const mediaMatch = query => window.matchMedia(query).matches;
  812. let platform = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
  813. const detect = () => platform();
  814. const r = (left, top) => {
  815. const translate = (x, y) => r(left + x, top + y);
  816. return {
  817. left,
  818. top,
  819. translate
  820. };
  821. };
  822. const SugarPosition = r;
  823. const get$1 = _DOC => {
  824. const doc = _DOC !== undefined ? _DOC.dom : document;
  825. const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
  826. const y = doc.body.scrollTop || doc.documentElement.scrollTop;
  827. return SugarPosition(x, y);
  828. };
  829. const get = _win => {
  830. const win = _win === undefined ? window : _win;
  831. if (detect().browser.isFirefox()) {
  832. return Optional.none();
  833. } else {
  834. return Optional.from(win.visualViewport);
  835. }
  836. };
  837. const bounds = (x, y, width, height) => ({
  838. x,
  839. y,
  840. width,
  841. height,
  842. right: x + width,
  843. bottom: y + height
  844. });
  845. const getBounds = _win => {
  846. const win = _win === undefined ? window : _win;
  847. const doc = win.document;
  848. const scroll = get$1(SugarElement.fromDom(doc));
  849. return get(win).fold(() => {
  850. const html = win.document.documentElement;
  851. const width = html.clientWidth;
  852. const height = html.clientHeight;
  853. return bounds(scroll.left, scroll.top, width, height);
  854. }, visualViewport => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
  855. };
  856. const bind = (name, callback, _win) => get(_win).map(visualViewport => {
  857. const handler = e => callback(fromRawEvent(e));
  858. visualViewport.addEventListener(name, handler);
  859. return { unbind: () => visualViewport.removeEventListener(name, handler) };
  860. }).getOrThunk(() => ({ unbind: noop }));
  861. var global$1 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
  862. var global = tinymce.util.Tools.resolve('tinymce.Env');
  863. const fireFullscreenStateChanged = (editor, state) => {
  864. editor.dispatch('FullscreenStateChanged', { state });
  865. };
  866. const option = name => editor => editor.options.get(name);
  867. const register$2 = editor => {
  868. const registerOption = editor.options.register;
  869. registerOption('fullscreen_native', {
  870. processor: 'boolean',
  871. default: false
  872. });
  873. };
  874. const getFullscreenNative = option('fullscreen_native');
  875. const getFullscreenRoot = editor => {
  876. const elem = SugarElement.fromDom(editor.getElement());
  877. return getShadowRoot(elem).map(getShadowHost).getOrThunk(() => getBody(owner(elem)));
  878. };
  879. const getFullscreenElement = root => {
  880. if (root.fullscreenElement !== undefined) {
  881. return root.fullscreenElement;
  882. } else if (root.msFullscreenElement !== undefined) {
  883. return root.msFullscreenElement;
  884. } else if (root.webkitFullscreenElement !== undefined) {
  885. return root.webkitFullscreenElement;
  886. } else {
  887. return null;
  888. }
  889. };
  890. const getFullscreenchangeEventName = () => {
  891. if (document.fullscreenElement !== undefined) {
  892. return 'fullscreenchange';
  893. } else if (document.msFullscreenElement !== undefined) {
  894. return 'MSFullscreenChange';
  895. } else if (document.webkitFullscreenElement !== undefined) {
  896. return 'webkitfullscreenchange';
  897. } else {
  898. return 'fullscreenchange';
  899. }
  900. };
  901. const requestFullscreen = sugarElem => {
  902. const elem = sugarElem.dom;
  903. if (elem.requestFullscreen) {
  904. elem.requestFullscreen();
  905. } else if (elem.msRequestFullscreen) {
  906. elem.msRequestFullscreen();
  907. } else if (elem.webkitRequestFullScreen) {
  908. elem.webkitRequestFullScreen();
  909. }
  910. };
  911. const exitFullscreen = sugarDoc => {
  912. const doc = sugarDoc.dom;
  913. if (doc.exitFullscreen) {
  914. doc.exitFullscreen();
  915. } else if (doc.msExitFullscreen) {
  916. doc.msExitFullscreen();
  917. } else if (doc.webkitCancelFullScreen) {
  918. doc.webkitCancelFullScreen();
  919. }
  920. };
  921. const isFullscreenElement = elem => elem.dom === getFullscreenElement(owner(elem).dom);
  922. const ancestors$1 = (scope, predicate, isRoot) => filter$1(parents(scope, isRoot), predicate);
  923. const siblings$1 = (scope, predicate) => filter$1(siblings$2(scope), predicate);
  924. const all = selector => all$1(selector);
  925. const ancestors = (scope, selector, isRoot) => ancestors$1(scope, e => is(e, selector), isRoot);
  926. const siblings = (scope, selector) => siblings$1(scope, e => is(e, selector));
  927. const attr = 'data-ephox-mobile-fullscreen-style';
  928. const siblingStyles = 'display:none!important;';
  929. const ancestorPosition = 'position:absolute!important;';
  930. const ancestorStyles = 'top:0!important;left:0!important;margin:0!important;padding:0!important;width:100%!important;height:100%!important;overflow:visible!important;';
  931. const bgFallback = 'background-color:rgb(255,255,255)!important;';
  932. const isAndroid = global.os.isAndroid();
  933. const matchColor = editorBody => {
  934. const color = get$2(editorBody, 'background-color');
  935. return color !== undefined && color !== '' ? 'background-color:' + color + '!important' : bgFallback;
  936. };
  937. const clobberStyles = (dom, container, editorBody) => {
  938. const gatherSiblings = element => {
  939. return siblings(element, '*:not(.tox-silver-sink)');
  940. };
  941. const clobber = clobberStyle => element => {
  942. const styles = get$3(element, 'style');
  943. const backup = styles === undefined ? 'no-styles' : styles.trim();
  944. if (backup === clobberStyle) {
  945. return;
  946. } else {
  947. set(element, attr, backup);
  948. setAll(element, dom.parseStyle(clobberStyle));
  949. }
  950. };
  951. const ancestors$1 = ancestors(container, '*');
  952. const siblings$1 = bind$3(ancestors$1, gatherSiblings);
  953. const bgColor = matchColor(editorBody);
  954. each$1(siblings$1, clobber(siblingStyles));
  955. each$1(ancestors$1, clobber(ancestorPosition + ancestorStyles + bgColor));
  956. const containerStyles = isAndroid === true ? '' : ancestorPosition;
  957. clobber(containerStyles + ancestorStyles + bgColor)(container);
  958. };
  959. const restoreStyles = dom => {
  960. const clobberedEls = all('[' + attr + ']');
  961. each$1(clobberedEls, element => {
  962. const restore = get$3(element, attr);
  963. if (restore !== 'no-styles') {
  964. setAll(element, dom.parseStyle(restore));
  965. } else {
  966. remove(element, 'style');
  967. }
  968. remove(element, attr);
  969. });
  970. };
  971. const DOM = global$1.DOM;
  972. const getScrollPos = () => getBounds(window);
  973. const setScrollPos = pos => window.scrollTo(pos.x, pos.y);
  974. const viewportUpdate = get().fold(() => ({
  975. bind: noop,
  976. unbind: noop
  977. }), visualViewport => {
  978. const editorContainer = value();
  979. const resizeBinder = unbindable();
  980. const scrollBinder = unbindable();
  981. const refreshScroll = () => {
  982. document.body.scrollTop = 0;
  983. document.documentElement.scrollTop = 0;
  984. };
  985. const refreshVisualViewport = () => {
  986. window.requestAnimationFrame(() => {
  987. editorContainer.on(container => setAll(container, {
  988. top: visualViewport.offsetTop + 'px',
  989. left: visualViewport.offsetLeft + 'px',
  990. height: visualViewport.height + 'px',
  991. width: visualViewport.width + 'px'
  992. }));
  993. });
  994. };
  995. const update = first(() => {
  996. refreshScroll();
  997. refreshVisualViewport();
  998. }, 50);
  999. const bind$1 = element => {
  1000. editorContainer.set(element);
  1001. update.throttle();
  1002. resizeBinder.set(bind('resize', update.throttle));
  1003. scrollBinder.set(bind('scroll', update.throttle));
  1004. };
  1005. const unbind = () => {
  1006. editorContainer.on(() => {
  1007. resizeBinder.clear();
  1008. scrollBinder.clear();
  1009. });
  1010. editorContainer.clear();
  1011. };
  1012. return {
  1013. bind: bind$1,
  1014. unbind
  1015. };
  1016. });
  1017. const toggleFullscreen = (editor, fullscreenState) => {
  1018. const body = document.body;
  1019. const documentElement = document.documentElement;
  1020. const editorContainer = editor.getContainer();
  1021. const editorContainerS = SugarElement.fromDom(editorContainer);
  1022. const fullscreenRoot = getFullscreenRoot(editor);
  1023. const fullscreenInfo = fullscreenState.get();
  1024. const editorBody = SugarElement.fromDom(editor.getBody());
  1025. const isTouch = global.deviceType.isTouch();
  1026. const editorContainerStyle = editorContainer.style;
  1027. const iframe = editor.iframeElement;
  1028. const iframeStyle = iframe.style;
  1029. const handleClasses = handler => {
  1030. handler(body, 'tox-fullscreen');
  1031. handler(documentElement, 'tox-fullscreen');
  1032. handler(editorContainer, 'tox-fullscreen');
  1033. getShadowRoot(editorContainerS).map(root => getShadowHost(root).dom).each(host => {
  1034. handler(host, 'tox-fullscreen');
  1035. handler(host, 'tox-shadowhost');
  1036. });
  1037. };
  1038. const cleanup = () => {
  1039. if (isTouch) {
  1040. restoreStyles(editor.dom);
  1041. }
  1042. handleClasses(DOM.removeClass);
  1043. viewportUpdate.unbind();
  1044. Optional.from(fullscreenState.get()).each(info => info.fullscreenChangeHandler.unbind());
  1045. };
  1046. if (!fullscreenInfo) {
  1047. const fullscreenChangeHandler = bind$1(owner(fullscreenRoot), getFullscreenchangeEventName(), _evt => {
  1048. if (getFullscreenNative(editor)) {
  1049. if (!isFullscreenElement(fullscreenRoot) && fullscreenState.get() !== null) {
  1050. toggleFullscreen(editor, fullscreenState);
  1051. }
  1052. }
  1053. });
  1054. const newFullScreenInfo = {
  1055. scrollPos: getScrollPos(),
  1056. containerWidth: editorContainerStyle.width,
  1057. containerHeight: editorContainerStyle.height,
  1058. containerTop: editorContainerStyle.top,
  1059. containerLeft: editorContainerStyle.left,
  1060. iframeWidth: iframeStyle.width,
  1061. iframeHeight: iframeStyle.height,
  1062. fullscreenChangeHandler
  1063. };
  1064. if (isTouch) {
  1065. clobberStyles(editor.dom, editorContainerS, editorBody);
  1066. }
  1067. iframeStyle.width = iframeStyle.height = '100%';
  1068. editorContainerStyle.width = editorContainerStyle.height = '';
  1069. handleClasses(DOM.addClass);
  1070. viewportUpdate.bind(editorContainerS);
  1071. editor.on('remove', cleanup);
  1072. fullscreenState.set(newFullScreenInfo);
  1073. if (getFullscreenNative(editor)) {
  1074. requestFullscreen(fullscreenRoot);
  1075. }
  1076. fireFullscreenStateChanged(editor, true);
  1077. } else {
  1078. fullscreenInfo.fullscreenChangeHandler.unbind();
  1079. if (getFullscreenNative(editor) && isFullscreenElement(fullscreenRoot)) {
  1080. exitFullscreen(owner(fullscreenRoot));
  1081. }
  1082. iframeStyle.width = fullscreenInfo.iframeWidth;
  1083. iframeStyle.height = fullscreenInfo.iframeHeight;
  1084. editorContainerStyle.width = fullscreenInfo.containerWidth;
  1085. editorContainerStyle.height = fullscreenInfo.containerHeight;
  1086. editorContainerStyle.top = fullscreenInfo.containerTop;
  1087. editorContainerStyle.left = fullscreenInfo.containerLeft;
  1088. cleanup();
  1089. setScrollPos(fullscreenInfo.scrollPos);
  1090. fullscreenState.set(null);
  1091. fireFullscreenStateChanged(editor, false);
  1092. editor.off('remove', cleanup);
  1093. }
  1094. };
  1095. const register$1 = (editor, fullscreenState) => {
  1096. editor.addCommand('mceFullScreen', () => {
  1097. toggleFullscreen(editor, fullscreenState);
  1098. });
  1099. };
  1100. const makeSetupHandler = (editor, fullscreenState) => api => {
  1101. api.setActive(fullscreenState.get() !== null);
  1102. const editorEventCallback = e => api.setActive(e.state);
  1103. editor.on('FullscreenStateChanged', editorEventCallback);
  1104. return () => editor.off('FullscreenStateChanged', editorEventCallback);
  1105. };
  1106. const register = (editor, fullscreenState) => {
  1107. const onAction = () => editor.execCommand('mceFullScreen');
  1108. editor.ui.registry.addToggleMenuItem('fullscreen', {
  1109. text: 'Fullscreen',
  1110. icon: 'fullscreen',
  1111. shortcut: 'Meta+Shift+F',
  1112. onAction,
  1113. onSetup: makeSetupHandler(editor, fullscreenState)
  1114. });
  1115. editor.ui.registry.addToggleButton('fullscreen', {
  1116. tooltip: 'Fullscreen',
  1117. icon: 'fullscreen',
  1118. onAction,
  1119. onSetup: makeSetupHandler(editor, fullscreenState)
  1120. });
  1121. };
  1122. var Plugin = () => {
  1123. global$2.add('fullscreen', editor => {
  1124. const fullscreenState = Cell(null);
  1125. if (editor.inline) {
  1126. return get$5(fullscreenState);
  1127. }
  1128. register$2(editor);
  1129. register$1(editor, fullscreenState);
  1130. register(editor, fullscreenState);
  1131. editor.addShortcut('Meta+Shift+F', '', 'mceFullScreen');
  1132. return get$5(fullscreenState);
  1133. });
  1134. };
  1135. Plugin();
  1136. })();