|
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 |
|
11 /*global tinymce:true */ |
|
12 |
|
13 // Internal unload handler will be called before the page is unloaded |
|
14 // Needs to be outside the plugin since it would otherwise keep |
|
15 // a reference to editor in closue scope |
|
16 /*eslint no-func-assign:0 */ |
|
17 tinymce._beforeUnloadHandler = function() { |
|
18 var msg; |
|
19 |
|
20 tinymce.each(tinymce.editors, function(editor) { |
|
21 // Store a draft for each editor instance |
|
22 if (editor.plugins.autosave) { |
|
23 editor.plugins.autosave.storeDraft(); |
|
24 } |
|
25 |
|
26 // Setup a return message if the editor is dirty |
|
27 if (!msg && editor.isDirty() && editor.getParam("autosave_ask_before_unload", true)) { |
|
28 msg = editor.translate("You have unsaved changes are you sure you want to navigate away?"); |
|
29 } |
|
30 }); |
|
31 |
|
32 return msg; |
|
33 }; |
|
34 |
|
35 tinymce.PluginManager.add('autosave', function(editor) { |
|
36 var settings = editor.settings, LocalStorage = tinymce.util.LocalStorage, prefix, started; |
|
37 |
|
38 prefix = settings.autosave_prefix || 'tinymce-autosave-{path}{query}-{id}-'; |
|
39 prefix = prefix.replace(/\{path\}/g, document.location.pathname); |
|
40 prefix = prefix.replace(/\{query\}/g, document.location.search); |
|
41 prefix = prefix.replace(/\{id\}/g, editor.id); |
|
42 |
|
43 function parseTime(time, defaultTime) { |
|
44 var multipels = { |
|
45 s: 1000, |
|
46 m: 60000 |
|
47 }; |
|
48 |
|
49 time = /^(\d+)([ms]?)$/.exec('' + (time || defaultTime)); |
|
50 |
|
51 return (time[2] ? multipels[time[2]] : 1) * parseInt(time, 10); |
|
52 } |
|
53 |
|
54 function hasDraft() { |
|
55 var time = parseInt(LocalStorage.getItem(prefix + "time"), 10) || 0; |
|
56 |
|
57 if (new Date().getTime() - time > settings.autosave_retention) { |
|
58 removeDraft(false); |
|
59 return false; |
|
60 } |
|
61 |
|
62 return true; |
|
63 } |
|
64 |
|
65 function removeDraft(fire) { |
|
66 LocalStorage.removeItem(prefix + "draft"); |
|
67 LocalStorage.removeItem(prefix + "time"); |
|
68 |
|
69 if (fire !== false) { |
|
70 editor.fire('RemoveDraft'); |
|
71 } |
|
72 } |
|
73 |
|
74 function storeDraft() { |
|
75 if (!isEmpty() && editor.isDirty()) { |
|
76 LocalStorage.setItem(prefix + "draft", editor.getContent({format: 'raw', no_events: true})); |
|
77 LocalStorage.setItem(prefix + "time", new Date().getTime()); |
|
78 editor.fire('StoreDraft'); |
|
79 } |
|
80 } |
|
81 |
|
82 function restoreDraft() { |
|
83 if (hasDraft()) { |
|
84 editor.setContent(LocalStorage.getItem(prefix + "draft"), {format: 'raw'}); |
|
85 editor.fire('RestoreDraft'); |
|
86 } |
|
87 } |
|
88 |
|
89 function startStoreDraft() { |
|
90 if (!started) { |
|
91 setInterval(function() { |
|
92 if (!editor.removed) { |
|
93 storeDraft(); |
|
94 } |
|
95 }, settings.autosave_interval); |
|
96 |
|
97 started = true; |
|
98 } |
|
99 } |
|
100 |
|
101 settings.autosave_interval = parseTime(settings.autosave_interval, '30s'); |
|
102 settings.autosave_retention = parseTime(settings.autosave_retention, '20m'); |
|
103 |
|
104 function postRender() { |
|
105 var self = this; |
|
106 |
|
107 self.disabled(!hasDraft()); |
|
108 |
|
109 editor.on('StoreDraft RestoreDraft RemoveDraft', function() { |
|
110 self.disabled(!hasDraft()); |
|
111 }); |
|
112 |
|
113 startStoreDraft(); |
|
114 } |
|
115 |
|
116 function restoreLastDraft() { |
|
117 editor.undoManager.beforeChange(); |
|
118 restoreDraft(); |
|
119 removeDraft(); |
|
120 editor.undoManager.add(); |
|
121 } |
|
122 |
|
123 editor.addButton('restoredraft', { |
|
124 title: 'Restore last draft', |
|
125 onclick: restoreLastDraft, |
|
126 onPostRender: postRender |
|
127 }); |
|
128 |
|
129 editor.addMenuItem('restoredraft', { |
|
130 text: 'Restore last draft', |
|
131 onclick: restoreLastDraft, |
|
132 onPostRender: postRender, |
|
133 context: 'file' |
|
134 }); |
|
135 |
|
136 function isEmpty(html) { |
|
137 var forcedRootBlockName = editor.settings.forced_root_block; |
|
138 |
|
139 html = tinymce.trim(typeof html == "undefined" ? editor.getBody().innerHTML : html); |
|
140 |
|
141 return html === '' || new RegExp( |
|
142 '^<' + forcedRootBlockName + '[^>]*>((\u00a0| |[ \t]|<br[^>]*>)+?|)<\/' + forcedRootBlockName + '>|<br>$', 'i' |
|
143 ).test(html); |
|
144 } |
|
145 |
|
146 if (editor.settings.autosave_restore_when_empty !== false) { |
|
147 editor.on('init', function() { |
|
148 if (hasDraft() && isEmpty()) { |
|
149 restoreDraft(); |
|
150 } |
|
151 }); |
|
152 |
|
153 editor.on('saveContent', function() { |
|
154 removeDraft(); |
|
155 }); |
|
156 } |
|
157 |
|
158 window.onbeforeunload = tinymce._beforeUnloadHandler; |
|
159 |
|
160 this.hasDraft = hasDraft; |
|
161 this.storeDraft = storeDraft; |
|
162 this.restoreDraft = restoreDraft; |
|
163 this.removeDraft = removeDraft; |
|
164 this.isEmpty = isEmpty; |
|
165 }); |