source: trunk/library/tiny_mce/plugins/autosave/editor_plugin_src.js @ 4829

Revision 4829, 13.4 KB checked in by airton, 13 years ago (diff)

Ticket #2146 - Implementacao da funcionalidade de multiplas assinaturas - Adicao da biblioteca TinyMCE

  • Property svn:executable set to *
Line 
1/**
2 * editor_plugin_src.js
3 *
4 * Copyright 2009, Moxiecode Systems AB
5 * Released under LGPL License.
6 *
7 * License: http://tinymce.moxiecode.com/license
8 * Contributing: http://tinymce.moxiecode.com/contributing
9 *
10 * Adds auto-save capability to the TinyMCE text editor to rescue content
11 * inadvertently lost. This plugin was originally developed by Speednet
12 * and that project can be found here: http://code.google.com/p/tinyautosave/
13 *
14 * TECHNOLOGY DISCUSSION:
15 *
16 * The plugin attempts to use the most advanced features available in the current browser to save
17 * as much content as possible.  There are a total of four different methods used to autosave the
18 * content.  In order of preference, they are:
19 *
20 * 1. localStorage - A new feature of HTML 5, localStorage can store megabytes of data per domain
21 * on the client computer. Data stored in the localStorage area has no expiration date, so we must
22 * manage expiring the data ourselves.  localStorage is fully supported by IE8, and it is supposed
23 * to be working in Firefox 3 and Safari 3.2, but in reality is is flaky in those browsers.  As
24 * HTML 5 gets wider support, the AutoSave plugin will use it automatically. In Windows Vista/7,
25 * localStorage is stored in the following folder:
26 * C:\Users\[username]\AppData\Local\Microsoft\Internet Explorer\DOMStore\[tempFolder]
27 *
28 * 2. sessionStorage - A new feature of HTML 5, sessionStorage works similarly to localStorage,
29 * except it is designed to expire after a certain amount of time.  Because the specification
30 * around expiration date/time is very loosely-described, it is preferrable to use locaStorage and
31 * manage the expiration ourselves.  sessionStorage has similar storage characteristics to
32 * localStorage, although it seems to have better support by Firefox 3 at the moment.  (That will
33 * certainly change as Firefox continues getting better at HTML 5 adoption.)
34 *
35 * 3. UserData - A very under-exploited feature of Microsoft Internet Explorer, UserData is a
36 * way to store up to 128K of data per "document", or up to 1MB of data per domain, on the client
37 * computer.  The feature is available for IE 5+, which makes it available for every version of IE
38 * supported by TinyMCE.  The content is persistent across browser restarts and expires on the
39 * date/time specified, just like a cookie.  However, the data is not cleared when the user clears
40 * cookies on the browser, which makes it well-suited for rescuing autosaved content.  UserData,
41 * like other Microsoft IE browser technologies, is implemented as a behavior attached to a
42 * specific DOM object, so in this case we attach the behavior to the same DOM element that the
43 * TinyMCE editor instance is attached to.
44 */
45
46(function(tinymce) {
47        // Setup constants to help the compressor to reduce script size
48        var PLUGIN_NAME = 'autosave',
49                RESTORE_DRAFT = 'restoredraft',
50                TRUE = true,
51                undefined,
52                unloadHandlerAdded,
53                Dispatcher = tinymce.util.Dispatcher;
54
55        /**
56         * This plugin adds auto-save capability to the TinyMCE text editor to rescue content
57         * inadvertently lost. By using localStorage.
58         *
59         * @class tinymce.plugins.AutoSave
60         */
61        tinymce.create('tinymce.plugins.AutoSave', {
62                /**
63                 * Initializes the plugin, this will be executed after the plugin has been created.
64                 * This call is done before the editor instance has finished it's initialization so use the onInit event
65                 * of the editor instance to intercept that event.
66                 *
67                 * @method init
68                 * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
69                 * @param {string} url Absolute URL to where the plugin is located.
70                 */
71                init : function(ed, url) {
72                        var self = this, settings = ed.settings;
73
74                        self.editor = ed;
75
76                        // Parses the specified time string into a milisecond number 10m, 10s etc.
77                        function parseTime(time) {
78                                var multipels = {
79                                        s : 1000,
80                                        m : 60000
81                                };
82
83                                time = /^(\d+)([ms]?)$/.exec('' + time);
84
85                                return (time[2] ? multipels[time[2]] : 1) * parseInt(time);
86                        };
87
88                        // Default config
89                        tinymce.each({
90                                ask_before_unload : TRUE,
91                                interval : '30s',
92                                retention : '20m',
93                                minlength : 50
94                        }, function(value, key) {
95                                key = PLUGIN_NAME + '_' + key;
96
97                                if (settings[key] === undefined)
98                                        settings[key] = value;
99                        });
100
101                        // Parse times
102                        settings.autosave_interval = parseTime(settings.autosave_interval);
103                        settings.autosave_retention = parseTime(settings.autosave_retention);
104
105                        // Register restore button
106                        ed.addButton(RESTORE_DRAFT, {
107                                title : PLUGIN_NAME + ".restore_content",
108                                onclick : function() {
109                                        if (ed.getContent({draft: true}).replace(/\s|&nbsp;|<\/?p[^>]*>|<br[^>]*>/gi, "").length > 0) {
110                                                // Show confirm dialog if the editor isn't empty
111                                                ed.windowManager.confirm(
112                                                        PLUGIN_NAME + ".warning_message",
113                                                        function(ok) {
114                                                                if (ok)
115                                                                        self.restoreDraft();
116                                                        }
117                                                );
118                                        } else
119                                                self.restoreDraft();
120                                }
121                        });
122
123                        // Enable/disable restoredraft button depending on if there is a draft stored or not
124                        ed.onNodeChange.add(function() {
125                                var controlManager = ed.controlManager;
126
127                                if (controlManager.get(RESTORE_DRAFT))
128                                        controlManager.setDisabled(RESTORE_DRAFT, !self.hasDraft());
129                        });
130
131                        ed.onInit.add(function() {
132                                // Check if the user added the restore button, then setup auto storage logic
133                                if (ed.controlManager.get(RESTORE_DRAFT)) {
134                                        // Setup storage engine
135                                        self.setupStorage(ed);
136
137                                        // Auto save contents each interval time
138                                        setInterval(function() {
139                                                self.storeDraft();
140                                                ed.nodeChanged();
141                                        }, settings.autosave_interval);
142                                }
143                        });
144
145                        /**
146                         * This event gets fired when a draft is stored to local storage.
147                         *
148                         * @event onStoreDraft
149                         * @param {tinymce.plugins.AutoSave} sender Plugin instance sending the event.
150                         * @param {Object} draft Draft object containing the HTML contents of the editor.
151                         */
152                        self.onStoreDraft = new Dispatcher(self);
153
154                        /**
155                         * This event gets fired when a draft is restored from local storage.
156                         *
157                         * @event onStoreDraft
158                         * @param {tinymce.plugins.AutoSave} sender Plugin instance sending the event.
159                         * @param {Object} draft Draft object containing the HTML contents of the editor.
160                         */
161                        self.onRestoreDraft = new Dispatcher(self);
162
163                        /**
164                         * This event gets fired when a draft removed/expired.
165                         *
166                         * @event onRemoveDraft
167                         * @param {tinymce.plugins.AutoSave} sender Plugin instance sending the event.
168                         * @param {Object} draft Draft object containing the HTML contents of the editor.
169                         */
170                        self.onRemoveDraft = new Dispatcher(self);
171
172                        // Add ask before unload dialog only add one unload handler
173                        if (!unloadHandlerAdded) {
174                                window.onbeforeunload = tinymce.plugins.AutoSave._beforeUnloadHandler;
175                                unloadHandlerAdded = TRUE;
176                        }
177                },
178
179                /**
180                 * Returns information about the plugin as a name/value array.
181                 * The current keys are longname, author, authorurl, infourl and version.
182                 *
183                 * @method getInfo
184                 * @return {Object} Name/value array containing information about the plugin.
185                 */
186                getInfo : function() {
187                        return {
188                                longname : 'Auto save',
189                                author : 'Moxiecode Systems AB',
190                                authorurl : 'http://tinymce.moxiecode.com',
191                                infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave',
192                                version : tinymce.majorVersion + "." + tinymce.minorVersion
193                        };
194                },
195
196                /**
197                 * Returns an expiration date UTC string.
198                 *
199                 * @method getExpDate
200                 * @return {String} Expiration date UTC string.
201                 */
202                getExpDate : function() {
203                        return new Date(
204                                new Date().getTime() + this.editor.settings.autosave_retention
205                        ).toUTCString();
206                },
207
208                /**
209                 * This method will setup the storage engine. If the browser has support for it.
210                 *
211                 * @method setupStorage
212                 */
213                setupStorage : function(ed) {
214                        var self = this, testKey = PLUGIN_NAME + '_test', testVal = "OK";
215
216                        self.key = PLUGIN_NAME + ed.id;
217
218                        // Loop though each storage engine type until we find one that works
219                        tinymce.each([
220                                function() {
221                                        // Try HTML5 Local Storage
222                                        if (localStorage) {
223                                                localStorage.setItem(testKey, testVal);
224
225                                                if (localStorage.getItem(testKey) === testVal) {
226                                                        localStorage.removeItem(testKey);
227
228                                                        return localStorage;
229                                                }
230                                        }
231                                },
232
233                                function() {
234                                        // Try HTML5 Session Storage
235                                        if (sessionStorage) {
236                                                sessionStorage.setItem(testKey, testVal);
237
238                                                if (sessionStorage.getItem(testKey) === testVal) {
239                                                        sessionStorage.removeItem(testKey);
240
241                                                        return sessionStorage;
242                                                }
243                                        }
244                                },
245
246                                function() {
247                                        // Try IE userData
248                                        if (tinymce.isIE) {
249                                                ed.getElement().style.behavior = "url('#default#userData')";
250
251                                                // Fake localStorage on old IE
252                                                return {
253                                                        autoExpires : TRUE,
254
255                                                        setItem : function(key, value) {
256                                                                var userDataElement = ed.getElement();
257
258                                                                userDataElement.setAttribute(key, value);
259                                                                userDataElement.expires = self.getExpDate();
260
261                                                                try {
262                                                                        userDataElement.save("TinyMCE");
263                                                                } catch (e) {
264                                                                        // Ignore, saving might fail if "Userdata Persistence" is disabled in IE
265                                                                }
266                                                        },
267
268                                                        getItem : function(key) {
269                                                                var userDataElement = ed.getElement();
270
271                                                                try {
272                                                                        userDataElement.load("TinyMCE");
273                                                                        return userDataElement.getAttribute(key);
274                                                                } catch (e) {
275                                                                        // Ignore, loading might fail if "Userdata Persistence" is disabled in IE
276                                                                        return null;
277                                                                }
278                                                        },
279
280                                                        removeItem : function(key) {
281                                                                ed.getElement().removeAttribute(key);
282                                                        }
283                                                };
284                                        }
285                                },
286                        ], function(setup) {
287                                // Try executing each function to find a suitable storage engine
288                                try {
289                                        self.storage = setup();
290
291                                        if (self.storage)
292                                                return false;
293                                } catch (e) {
294                                        // Ignore
295                                }
296                        });
297                },
298
299                /**
300                 * This method will store the current contents in the the storage engine.
301                 *
302                 * @method storeDraft
303                 */
304                storeDraft : function() {
305                        var self = this, storage = self.storage, editor = self.editor, expires, content;
306
307                        // Is the contents dirty
308                        if (storage) {
309                                // If there is no existing key and the contents hasn't been changed since
310                                // it's original value then there is no point in saving a draft
311                                if (!storage.getItem(self.key) && !editor.isDirty())
312                                        return;
313
314                                // Store contents if the contents if longer than the minlength of characters
315                                content = editor.getContent({draft: true});
316                                if (content.length > editor.settings.autosave_minlength) {
317                                        expires = self.getExpDate();
318
319                                        // Store expiration date if needed IE userData has auto expire built in
320                                        if (!self.storage.autoExpires)
321                                                self.storage.setItem(self.key + "_expires", expires);
322
323                                        self.storage.setItem(self.key, content);
324                                        self.onStoreDraft.dispatch(self, {
325                                                expires : expires,
326                                                content : content
327                                        });
328                                }
329                        }
330                },
331
332                /**
333                 * This method will restore the contents from the storage engine back to the editor.
334                 *
335                 * @method restoreDraft
336                 */
337                restoreDraft : function() {
338                        var self = this, storage = self.storage;
339
340                        if (storage) {
341                                content = storage.getItem(self.key);
342
343                                if (content) {
344                                        self.editor.setContent(content);
345                                        self.onRestoreDraft.dispatch(self, {
346                                                content : content
347                                        });
348                                }
349                        }
350                },
351
352                /**
353                 * This method will return true/false if there is a local storage draft available.
354                 *
355                 * @method hasDraft
356                 * @return {boolean} true/false state if there is a local draft.
357                 */
358                hasDraft : function() {
359                        var self = this, storage = self.storage, expDate, exists;
360
361                        if (storage) {
362                                // Does the item exist at all
363                                exists = !!storage.getItem(self.key);
364                                if (exists) {
365                                        // Storage needs autoexpire
366                                        if (!self.storage.autoExpires) {
367                                                expDate = new Date(storage.getItem(self.key + "_expires"));
368
369                                                // Contents hasn't expired
370                                                if (new Date().getTime() < expDate.getTime())
371                                                        return TRUE;
372
373                                                // Remove it if it has
374                                                self.removeDraft();
375                                        } else
376                                                return TRUE;
377                                }
378                        }
379
380                        return false;
381                },
382
383                /**
384                 * Removes the currently stored draft.
385                 *
386                 * @method removeDraft
387                 */
388                removeDraft : function() {
389                        var self = this, storage = self.storage, key = self.key, content;
390
391                        if (storage) {
392                                // Get current contents and remove the existing draft
393                                content = storage.getItem(key);
394                                storage.removeItem(key);
395                                storage.removeItem(key + "_expires");
396
397                                // Dispatch remove event if we had any contents
398                                if (content) {
399                                        self.onRemoveDraft.dispatch(self, {
400                                                content : content
401                                        });
402                                }
403                        }
404                },
405
406                "static" : {
407                        // Internal unload handler will be called before the page is unloaded
408                        _beforeUnloadHandler : function(e) {
409                                var msg;
410
411                                tinymce.each(tinyMCE.editors, function(ed) {
412                                        // Store a draft for each editor instance
413                                        if (ed.plugins.autosave)
414                                                ed.plugins.autosave.storeDraft();
415
416                                        // Never ask in fullscreen mode
417                                        if (ed.getParam("fullscreen_is_enabled"))
418                                                return;
419
420                                        // Setup a return message if the editor is dirty
421                                        if (!msg && ed.isDirty() && ed.getParam("autosave_ask_before_unload"))
422                                                msg = ed.getLang("autosave.unload_msg");
423                                });
424
425                                return msg;
426                        }
427                }
428        });
429
430        tinymce.PluginManager.add('autosave', tinymce.plugins.AutoSave);
431})(tinymce);
Note: See TracBrowser for help on using the repository browser.