plugin.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /**
  2. * plugin.js
  3. *
  4. * Copyright, Moxiecode Systems AB
  5. * Released under LGPL License.
  6. *
  7. * License: http://www.tinymce.com/license
  8. * Contributing: http://www.tinymce.com/contributing
  9. */
  10. /*global tinymce:true */
  11. tinymce.PluginManager.add('autosave', function(editor) {
  12. var settings = editor.settings, LocalStorage = tinymce.util.LocalStorage, prefix, started;
  13. prefix = settings.autosave_prefix || 'tinymce-autosave-{path}{query}-{id}-';
  14. prefix = prefix.replace(/\{path\}/g, document.location.pathname);
  15. prefix = prefix.replace(/\{query\}/g, document.location.search);
  16. prefix = prefix.replace(/\{id\}/g, editor.id);
  17. function parseTime(time, defaultTime) {
  18. var multipels = {
  19. s: 1000,
  20. m: 60000
  21. };
  22. time = /^(\d+)([ms]?)$/.exec('' + (time || defaultTime));
  23. return (time[2] ? multipels[time[2]] : 1) * parseInt(time, 10);
  24. }
  25. function hasDraft() {
  26. var time = parseInt(LocalStorage.getItem(prefix + "time"), 10) || 0;
  27. if (new Date().getTime() - time > settings.autosave_retention) {
  28. removeDraft(false);
  29. return false;
  30. }
  31. return true;
  32. }
  33. function removeDraft(fire) {
  34. LocalStorage.removeItem(prefix + "draft");
  35. LocalStorage.removeItem(prefix + "time");
  36. if (fire !== false) {
  37. editor.fire('RemoveDraft');
  38. }
  39. }
  40. function storeDraft() {
  41. if (!isEmpty() && editor.isDirty()) {
  42. LocalStorage.setItem(prefix + "draft", editor.getContent({format: 'raw', no_events: true}));
  43. LocalStorage.setItem(prefix + "time", new Date().getTime());
  44. editor.fire('StoreDraft');
  45. }
  46. }
  47. function restoreDraft() {
  48. if (hasDraft()) {
  49. editor.setContent(LocalStorage.getItem(prefix + "draft"), {format: 'raw'});
  50. editor.fire('RestoreDraft');
  51. }
  52. }
  53. function startStoreDraft() {
  54. if (!started) {
  55. setInterval(function() {
  56. if (!editor.removed) {
  57. storeDraft();
  58. }
  59. }, settings.autosave_interval);
  60. started = true;
  61. }
  62. }
  63. settings.autosave_interval = parseTime(settings.autosave_interval, '30s');
  64. settings.autosave_retention = parseTime(settings.autosave_retention, '20m');
  65. function postRender() {
  66. var self = this;
  67. self.disabled(!hasDraft());
  68. editor.on('StoreDraft RestoreDraft RemoveDraft', function() {
  69. self.disabled(!hasDraft());
  70. });
  71. startStoreDraft();
  72. }
  73. function restoreLastDraft() {
  74. editor.undoManager.beforeChange();
  75. restoreDraft();
  76. removeDraft();
  77. editor.undoManager.add();
  78. }
  79. editor.addButton('restoredraft', {
  80. title: 'Restore last draft',
  81. onclick: restoreLastDraft,
  82. onPostRender: postRender
  83. });
  84. editor.addMenuItem('restoredraft', {
  85. text: 'Restore last draft',
  86. onclick: restoreLastDraft,
  87. onPostRender: postRender,
  88. context: 'file'
  89. });
  90. // Internal unload handler will be called before the page is unloaded
  91. function beforeUnloadHandler() {
  92. var msg;
  93. tinymce.each(tinymce.editors, function(editor) {
  94. // Store a draft for each editor instance
  95. if (editor.plugins.autosave) {
  96. editor.plugins.autosave.storeDraft();
  97. }
  98. // Setup a return message if the editor is dirty
  99. if (!msg && editor.isDirty() && editor.getParam("autosave_ask_before_unload", true)) {
  100. msg = editor.translate("You have unsaved changes are you sure you want to navigate away?");
  101. }
  102. });
  103. return msg;
  104. }
  105. function isEmpty(html) {
  106. var forcedRootBlockName = editor.settings.forced_root_block;
  107. html = tinymce.trim(typeof(html) == "undefined" ? editor.getBody().innerHTML : html);
  108. return html === '' || new RegExp(
  109. '^<' + forcedRootBlockName + '[^>]*>((\u00a0|&nbsp;|[ \t]|<br[^>]*>)+?|)<\/' + forcedRootBlockName + '>|<br>$', 'i'
  110. ).test(html);
  111. }
  112. if (editor.settings.autosave_restore_when_empty !== false) {
  113. editor.on('init', function() {
  114. if (hasDraft() && isEmpty()) {
  115. restoreDraft();
  116. }
  117. });
  118. editor.on('saveContent', function() {
  119. removeDraft();
  120. });
  121. }
  122. window.onbeforeunload = beforeUnloadHandler;
  123. this.hasDraft = hasDraft;
  124. this.storeDraft = storeDraft;
  125. this.restoreDraft = restoreDraft;
  126. this.removeDraft = removeDraft;
  127. this.isEmpty = isEmpty;
  128. });