plugin.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /**
  2. * TinyMCE version 6.0.3 (2022-05-25)
  3. */
  4. (function () {
  5. 'use strict';
  6. var global$4 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  7. const hasProto = (v, constructor, predicate) => {
  8. var _a;
  9. if (predicate(v, constructor.prototype)) {
  10. return true;
  11. } else {
  12. return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
  13. }
  14. };
  15. const typeOf = x => {
  16. const t = typeof x;
  17. if (x === null) {
  18. return 'null';
  19. } else if (t === 'object' && Array.isArray(x)) {
  20. return 'array';
  21. } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
  22. return 'string';
  23. } else {
  24. return t;
  25. }
  26. };
  27. const isType = type => value => typeOf(value) === type;
  28. const eq = t => a => t === a;
  29. const isString = isType('string');
  30. const isUndefined = eq(undefined);
  31. var global$3 = tinymce.util.Tools.resolve('tinymce.util.Delay');
  32. var global$2 = tinymce.util.Tools.resolve('tinymce.util.LocalStorage');
  33. var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  34. const fireRestoreDraft = editor => editor.dispatch('RestoreDraft');
  35. const fireStoreDraft = editor => editor.dispatch('StoreDraft');
  36. const fireRemoveDraft = editor => editor.dispatch('RemoveDraft');
  37. const parse = timeString => {
  38. const multiples = {
  39. s: 1000,
  40. m: 60000
  41. };
  42. const parsedTime = /^(\d+)([ms]?)$/.exec(timeString);
  43. return (parsedTime[2] ? multiples[parsedTime[2]] : 1) * parseInt(timeString, 10);
  44. };
  45. const option = name => editor => editor.options.get(name);
  46. const register$1 = editor => {
  47. const registerOption = editor.options.register;
  48. const timeProcessor = value => {
  49. const valid = isString(value);
  50. if (valid) {
  51. return {
  52. value: parse(value),
  53. valid
  54. };
  55. } else {
  56. return {
  57. valid: false,
  58. message: 'Must be a string.'
  59. };
  60. }
  61. };
  62. registerOption('autosave_ask_before_unload', {
  63. processor: 'boolean',
  64. default: true
  65. });
  66. registerOption('autosave_prefix', {
  67. processor: 'string',
  68. default: 'tinymce-autosave-{path}{query}{hash}-{id}-'
  69. });
  70. registerOption('autosave_restore_when_empty', {
  71. processor: 'boolean',
  72. default: false
  73. });
  74. registerOption('autosave_interval', {
  75. processor: timeProcessor,
  76. default: '30s'
  77. });
  78. registerOption('autosave_retention', {
  79. processor: timeProcessor,
  80. default: '20m'
  81. });
  82. };
  83. const shouldAskBeforeUnload = option('autosave_ask_before_unload');
  84. const shouldRestoreWhenEmpty = option('autosave_restore_when_empty');
  85. const getAutoSaveInterval = option('autosave_interval');
  86. const getAutoSaveRetention = option('autosave_retention');
  87. const getAutoSavePrefix = editor => {
  88. const location = document.location;
  89. return editor.options.get('autosave_prefix').replace(/{path}/g, location.pathname).replace(/{query}/g, location.search).replace(/{hash}/g, location.hash).replace(/{id}/g, editor.id);
  90. };
  91. const isEmpty = (editor, html) => {
  92. if (isUndefined(html)) {
  93. return editor.dom.isEmpty(editor.getBody());
  94. } else {
  95. const trimmedHtml = global$1.trim(html);
  96. if (trimmedHtml === '') {
  97. return true;
  98. } else {
  99. const fragment = new DOMParser().parseFromString(trimmedHtml, 'text/html');
  100. return editor.dom.isEmpty(fragment);
  101. }
  102. }
  103. };
  104. const hasDraft = editor => {
  105. const time = parseInt(global$2.getItem(getAutoSavePrefix(editor) + 'time'), 10) || 0;
  106. if (new Date().getTime() - time > getAutoSaveRetention(editor)) {
  107. removeDraft(editor, false);
  108. return false;
  109. }
  110. return true;
  111. };
  112. const removeDraft = (editor, fire) => {
  113. const prefix = getAutoSavePrefix(editor);
  114. global$2.removeItem(prefix + 'draft');
  115. global$2.removeItem(prefix + 'time');
  116. if (fire !== false) {
  117. fireRemoveDraft(editor);
  118. }
  119. };
  120. const storeDraft = editor => {
  121. const prefix = getAutoSavePrefix(editor);
  122. if (!isEmpty(editor) && editor.isDirty()) {
  123. global$2.setItem(prefix + 'draft', editor.getContent({
  124. format: 'raw',
  125. no_events: true
  126. }));
  127. global$2.setItem(prefix + 'time', new Date().getTime().toString());
  128. fireStoreDraft(editor);
  129. }
  130. };
  131. const restoreDraft = editor => {
  132. const prefix = getAutoSavePrefix(editor);
  133. if (hasDraft(editor)) {
  134. editor.setContent(global$2.getItem(prefix + 'draft'), { format: 'raw' });
  135. fireRestoreDraft(editor);
  136. }
  137. };
  138. const startStoreDraft = editor => {
  139. const interval = getAutoSaveInterval(editor);
  140. global$3.setEditorInterval(editor, () => {
  141. storeDraft(editor);
  142. }, interval);
  143. };
  144. const restoreLastDraft = editor => {
  145. editor.undoManager.transact(() => {
  146. restoreDraft(editor);
  147. removeDraft(editor);
  148. });
  149. editor.focus();
  150. };
  151. const get = editor => ({
  152. hasDraft: () => hasDraft(editor),
  153. storeDraft: () => storeDraft(editor),
  154. restoreDraft: () => restoreDraft(editor),
  155. removeDraft: fire => removeDraft(editor, fire),
  156. isEmpty: html => isEmpty(editor, html)
  157. });
  158. var global = tinymce.util.Tools.resolve('tinymce.EditorManager');
  159. const setup = editor => {
  160. editor.editorManager.on('BeforeUnload', e => {
  161. let msg;
  162. global$1.each(global.get(), editor => {
  163. if (editor.plugins.autosave) {
  164. editor.plugins.autosave.storeDraft();
  165. }
  166. if (!msg && editor.isDirty() && shouldAskBeforeUnload(editor)) {
  167. msg = editor.translate('You have unsaved changes are you sure you want to navigate away?');
  168. }
  169. });
  170. if (msg) {
  171. e.preventDefault();
  172. e.returnValue = msg;
  173. }
  174. });
  175. };
  176. const makeSetupHandler = editor => api => {
  177. api.setEnabled(hasDraft(editor));
  178. const editorEventCallback = () => api.setEnabled(hasDraft(editor));
  179. editor.on('StoreDraft RestoreDraft RemoveDraft', editorEventCallback);
  180. return () => editor.off('StoreDraft RestoreDraft RemoveDraft', editorEventCallback);
  181. };
  182. const register = editor => {
  183. startStoreDraft(editor);
  184. editor.ui.registry.addButton('restoredraft', {
  185. tooltip: 'Restore last draft',
  186. icon: 'restore-draft',
  187. onAction: () => {
  188. restoreLastDraft(editor);
  189. },
  190. onSetup: makeSetupHandler(editor)
  191. });
  192. editor.ui.registry.addMenuItem('restoredraft', {
  193. text: 'Restore last draft',
  194. icon: 'restore-draft',
  195. onAction: () => {
  196. restoreLastDraft(editor);
  197. },
  198. onSetup: makeSetupHandler(editor)
  199. });
  200. };
  201. var Plugin = () => {
  202. global$4.add('autosave', editor => {
  203. register$1(editor);
  204. setup(editor);
  205. register(editor);
  206. editor.on('init', () => {
  207. if (shouldRestoreWhenEmpty(editor) && editor.dom.isEmpty(editor.getBody())) {
  208. restoreDraft(editor);
  209. }
  210. });
  211. return get(editor);
  212. });
  213. };
  214. Plugin();
  215. })();