plugin.js 38 KB

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