AutoSave.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. define("dojox/editor/plugins/AutoSave", [
  2. "dojo",
  3. "dijit", // _scopeName
  4. "dojox",
  5. "dijit/_base/manager", // getUniqueId()
  6. "dijit/_base/popup",
  7. "dijit/_Widget",
  8. "dijit/_TemplatedMixin",
  9. "dijit/_WidgetsInTemplateMixin",
  10. "dijit/Dialog",
  11. "dijit/MenuItem",
  12. "dijit/Menu",
  13. "dijit/form/Button",
  14. "dijit/form/ComboButton",
  15. "dijit/form/ComboBox",
  16. "dijit/form/_TextBoxMixin", // selectInputText()
  17. "dijit/form/TextBox",
  18. "dijit/TooltipDialog",
  19. "dijit/_editor/_Plugin",
  20. "dojo/_base/connect",
  21. "dojo/_base/declare",
  22. "dojo/date/locale",
  23. "dojo/i18n",
  24. "dojo/string",
  25. "dojox/editor/plugins/Save",
  26. "dojo/i18n!dojox/editor/plugins/nls/AutoSave"
  27. ], function(dojo, dijit, dojox) {
  28. dojo.experimental("dojox.editor.plugins.AutoSave");
  29. dojo.declare("dojox.editor.plugins._AutoSaveSettingDialog", [dijit._Widget, dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin], {
  30. // dialogTitle [public] String
  31. // The tile of the Auto-Save setting dialog
  32. dialogTitle: "",
  33. // dialogDescription [public] String
  34. // The description of the Auto-Save setting dialog
  35. dialogDescription: "",
  36. // paramName [public] String
  37. // The name of the parameter (Auto-Save Interval)
  38. paramName: "",
  39. // paramLabel [public] String
  40. // Minute
  41. paramLabel: "",
  42. // btnOk [public] String
  43. // The label of the OK button
  44. btnOk: "",
  45. // btnCancel [public] String
  46. // The label of the Cancel button
  47. btnCancel: "",
  48. widgetsInTemplate: true,
  49. templateString:
  50. "<span id='${dialogId}' class='dijit dijitReset dijitInline' tabindex='-1'>" +
  51. "<div dojoType='dijit.Dialog' title='${dialogTitle}' dojoAttachPoint='dialog' " +
  52. "class='dijitEditorAutoSaveSettingDialog'>" +
  53. "<div tabindex='-1'>${dialogDescription}</div>" +
  54. "<div tabindex='-1' class='dijitEditorAutoSaveSettingInputArea'>${paramName}</div>" +
  55. "<div class='dijitEditorAutoSaveSettingInputArea' tabindex='-1'>" +
  56. "<input class='textBox' dojoType='dijit.form.TextBox' id='${textBoxId}' required='false' intermediateChanges='true' " +
  57. "selectOnClick='true' required='true' dojoAttachPoint='intBox' " +
  58. "dojoAttachEvent='onKeyDown: _onKeyDown, onChange: _onChange'/>" +
  59. "<label class='dijitLeft dijitInline boxLabel' " +
  60. "for='${textBoxId}' tabindex='-1'>${paramLabel}</label>" +
  61. "</div>" +
  62. "<div class='dijitEditorAutoSaveSettingButtonArea' tabindex='-1'>" +
  63. "<button dojoType='dijit.form.Button' dojoAttachEvent='onClick: onOk'>${btnOk}</button>" +
  64. "<button dojoType='dijit.form.Button' dojoAttachEvent='onClick: onCancel'>${btnCancel}</button>" +
  65. "</div>" +
  66. "</div>" +
  67. "</span>",
  68. postMixInProperties: function(){
  69. this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
  70. this.dialogId = this.id + "_dialog";
  71. this.textBoxId = this.id + "_textBox";
  72. },
  73. show: function(){
  74. // summary:
  75. // Display the setting dialog. If the internal interval value is ""
  76. // set it to zero
  77. // tags:
  78. // public
  79. if(this._value == ""){
  80. this._value = 0;
  81. this.intBox.set("value", 0);
  82. }else{
  83. this.intBox.set("value", this._value);
  84. }
  85. this.dialog.show();
  86. dijit.selectInputText(this.intBox.focusNode);
  87. },
  88. hide: function(){
  89. // summray:
  90. // Hide the setting dialog.
  91. // tags:
  92. // public
  93. this.dialog.hide();
  94. },
  95. onOk: function(){
  96. // summary:
  97. // Handle the OK event and close the dialog.
  98. // tags:
  99. // public
  100. this.dialog.hide();
  101. },
  102. onCancel: function(){
  103. // summary:
  104. // Handle the Cancel event and close the dialog.
  105. // tags:
  106. // public
  107. this.dialog.hide();
  108. },
  109. _onKeyDown: function(evt){
  110. // summary:
  111. // Handle the keydown event
  112. // tags:
  113. // private
  114. if(evt.keyCode == dojo.keys.ENTER){
  115. this.onOk();
  116. }
  117. },
  118. _onChange: function(/*String*/ val){
  119. // summary:
  120. // Check if the value is between 1 - 999.
  121. // tags:
  122. // public
  123. if(this._isValidValue(val)){
  124. this._value = val;
  125. }else{
  126. this.intBox.set("value", this._value);
  127. }
  128. },
  129. _setValueAttr: function(/*String*/ val){
  130. // summary:
  131. // Set the value attribute if it is acceptable
  132. // val:
  133. // The invertal value
  134. // tags:
  135. // private
  136. if(this._isValidValue(val)){
  137. this._value = val;
  138. }
  139. },
  140. _getValueAttr: function(){
  141. // summary:
  142. // Get the interval value
  143. // tags:
  144. // protected
  145. return this._value;
  146. },
  147. _isValidValue: function(/*String*/ val){
  148. // summary:
  149. // Check if this value between 1- 999
  150. // tags:
  151. // private
  152. var regExp = /^\d{0,3}$/,
  153. _v = String(val);
  154. return Boolean(_v.match ? _v.match(regExp) : "");
  155. }
  156. });
  157. dojo.declare("dojox.editor.plugins.AutoSave", dojox.editor.plugins.Save, {
  158. // summary:
  159. // This plugin provides the auto save capability to the editor. The
  160. // plugin saves the content of the editor in interval. When
  161. // the save action is performed, the document in the editor frame
  162. // will be posted to the URL provided, or none, if none provided.
  163. // url [public] String
  164. // The URL to POST the content back to. Used by the save function.
  165. url: "",
  166. // logErrors [public] boolean
  167. // Boolean flag to indicate that the default action for save and
  168. // error handlers is to just log to console. Default is true.
  169. logResults: true,
  170. // interval [public] Number
  171. // The interval to perform the save action.
  172. interval: 0,
  173. // _iconClassPrefix [private] String
  174. // This prefix of the CSS class
  175. _iconClassPrefix: "dijitEditorIconAutoSave",
  176. // _MIN [private const] Number
  177. // Default 1 minute
  178. _MIN: 60000,
  179. _setIntervalAttr: function(val){
  180. // summary:
  181. // Set the interval value.
  182. // Delay the boundary check to _isValidValue of the dialog class
  183. // val:
  184. // The interval value.
  185. // tags:
  186. // private
  187. this.interval = val;
  188. },
  189. _getIntervalAttr: function(){
  190. // summary:
  191. // Get the interval value
  192. // tags:
  193. // private
  194. return this._interval;
  195. },
  196. setEditor: function(editor){
  197. // summary:
  198. // Over-ride for the setting of the editor. No toggle button for
  199. // this plugin. And start to save the content of the editor in
  200. // interval
  201. // editor: Object
  202. // The editor to configure for this plugin to use.
  203. this.editor = editor;
  204. this._strings = dojo.i18n.getLocalization("dojox.editor.plugins", "AutoSave");
  205. this._initButton();
  206. this._saveSettingDialog = new dojox.editor.plugins._AutoSaveSettingDialog({
  207. "dialogTitle": this._strings["saveSettingdialogTitle"],
  208. "dialogDescription": this._strings["saveSettingdialogDescription"],
  209. "paramName": this._strings["saveSettingdialogParamName"],
  210. "paramLabel": this._strings["saveSettingdialogParamLabel"],
  211. "btnOk": this._strings["saveSettingdialogButtonOk"],
  212. "btnCancel": this._strings["saveSettingdialogButtonCancel"]
  213. });
  214. this.connect(this._saveSettingDialog, "onOk", "_onDialogOk");
  215. var pd = (this._promDialog = new dijit.TooltipDialog());
  216. pd.startup();
  217. pd.set("content", "");
  218. },
  219. _initButton: function(){
  220. var menu = new dijit.Menu({
  221. style: "display: none"
  222. }),
  223. menuItemSave = new dijit.MenuItem({
  224. iconClass: this._iconClassPrefix + "Default " + this._iconClassPrefix,
  225. label: this._strings["saveLabel"]
  226. }),
  227. menuItemAutoSave = (this._menuItemAutoSave = new dijit.MenuItem({
  228. iconClass: this._iconClassPrefix + "Setting " + this._iconClassPrefix,
  229. label: this._strings["saveSettingLabelOn"]
  230. }));
  231. menu.addChild(menuItemSave);
  232. menu.addChild(menuItemAutoSave);
  233. this.button = new dijit.form.ComboButton({
  234. label: this._strings["saveLabel"],
  235. iconClass: this._iconClassPrefix + "Default " + this._iconClassPrefix,
  236. showLabel: false,
  237. dropDown: menu
  238. });
  239. this.connect(this.button, "onClick", "_save");
  240. this.connect(menuItemSave, "onClick", "_save");
  241. this._menuItemAutoSaveClickHandler = dojo.connect(menuItemAutoSave, "onClick", this, "_showAutSaveSettingDialog");
  242. },
  243. _showAutSaveSettingDialog: function(){
  244. // summary:
  245. // Show the setting dialog
  246. // tags:
  247. // private
  248. var dialog = this._saveSettingDialog;
  249. dialog.set("value", this.interval);
  250. dialog.show();
  251. },
  252. _onDialogOk: function(){
  253. // summary:
  254. // If the interval is set (larger than 0), enable auto-save.
  255. // tags:
  256. // private
  257. var interval = (this.interval = this._saveSettingDialog.get("value") * this._MIN);
  258. if(interval > 0){
  259. this._setSaveInterval(interval);
  260. // Change the menu "Set Auto-Save Interval..." to "Turn off Auto-Save"
  261. // Connect it to another handler that terminates the auto-save.
  262. dojo.disconnect(this._menuItemAutoSaveClickHandler);
  263. this._menuItemAutoSave.set("label", this._strings["saveSettingLabelOff"]);
  264. this._menuItemAutoSaveClickHandler = dojo.connect(this._menuItemAutoSave, "onClick", this, "_onStopClick");
  265. // Change the icon of the main button to auto-save style
  266. this.button.set("iconClass", this._iconClassPrefix + "Setting " + this._iconClassPrefix);
  267. }
  268. },
  269. _onStopClick: function(){
  270. // summary:
  271. // Stop auto-save
  272. // tags:
  273. // private
  274. this._clearSaveInterval();
  275. // Change the menu "Turn off Auto-Save" to "Set Auto-Save Interval...".
  276. // Connect it to another handler that show the setting dialog.
  277. dojo.disconnect(this._menuItemAutoSaveClickHandler);
  278. this._menuItemAutoSave.set("label", this._strings["saveSettingLabelOn"]);
  279. this._menuItemAutoSaveClickHandler = dojo.connect(this._menuItemAutoSave, "onClick", this, "_showAutSaveSettingDialog");
  280. // Change the icon of the main button
  281. this.button.set("iconClass", this._iconClassPrefix + "Default " + this._iconClassPrefix);
  282. },
  283. _setSaveInterval: function(/*Number*/ interval){
  284. // summary:
  285. // Function to trigger saving of the editor document
  286. // tags:
  287. // private
  288. if(interval <= 0){
  289. return;
  290. }
  291. this._clearSaveInterval();
  292. this._intervalHandler = setInterval(dojo.hitch(this, function(){
  293. if(!this._isWorking && !this.get("disabled")){
  294. // If the plugin is not disabled (ViewSource, etc.)
  295. // and not working. Do saving!
  296. this._isWorking = true;
  297. this._save();
  298. }
  299. }), interval);
  300. },
  301. _clearSaveInterval: function(){
  302. if(this._intervalHandler){
  303. clearInterval(this._intervalHandler);
  304. this._intervalHandler = null;
  305. }
  306. },
  307. onSuccess: function(resp, ioargs){
  308. // summary:
  309. // User over-ridable save success function for editor content.
  310. // resp:
  311. // The response from the server, if any, in text format.
  312. // tags:
  313. // public
  314. this.button.set("disabled", false);
  315. // Show the successful message
  316. this._promDialog.set("content", dojo.string.substitute(
  317. this._strings["saveMessageSuccess"], {"0": dojo.date.locale.format(new Date(), {selector: "time"})}));
  318. dijit.popup.open({popup: this._promDialog, around: this.button.domNode});
  319. this._promDialogTimeout = setTimeout(dojo.hitch(this, function(){
  320. clearTimeout(this._promDialogTimeout);
  321. this._promDialogTimeout = null;
  322. dijit.popup.close(this._promDialog);
  323. }), 3000);
  324. this._isWorking = false;
  325. if(this.logResults){
  326. console.log(resp);
  327. }
  328. },
  329. onError: function(error, ioargs){
  330. // summary:
  331. // User over-ridable save success function for editor content.
  332. // resp:
  333. // The response from the server, if any, in text format.
  334. // tags:
  335. // public
  336. this.button.set("disabled", false);
  337. // Show the failure message
  338. this._promDialog.set("content", dojo.string.substitute(
  339. this._strings["saveMessageFail"], {"0": dojo.date.locale.format(new Date(), {selector: "time"})}));
  340. dijit.popup.open({popup: this._promDialog, around: this.button.domNode});
  341. this._promDialogTimeout = setTimeout(dojo.hitch(this, function(){
  342. clearTimeout(this._promDialogTimeout);
  343. this._promDialogTimeout = null;
  344. dijit.popup.close(this._promDialog);
  345. }), 3000);
  346. this._isWorking = false;
  347. if(this.logResults){
  348. console.log(error);
  349. }
  350. },
  351. destroy: function(){
  352. // summary:
  353. // Cleanup of our plugin.
  354. this.inherited(arguments);
  355. this._menuItemAutoSave = null;
  356. if(this._promDialogTimeout){
  357. clearTimeout(this._promDialogTimeout);
  358. this._promDialogTimeout = null;
  359. dijit.popup.close(this._promDialog);
  360. }
  361. this._clearSaveInterval();
  362. if(this._saveSettingDialog){
  363. this._saveSettingDialog.destroyRecursive();
  364. this._destroyRecursive = null;
  365. }
  366. if(this._menuItemAutoSaveClickHandler){
  367. dojo.disconnect(this._menuItemAutoSaveClickHandler);
  368. this._menuItemAutoSaveClickHandler = null;
  369. }
  370. }
  371. });
  372. // Register this plugin.
  373. dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
  374. if(o.plugin){ return; }
  375. var name = o.args.name.toLowerCase();
  376. if(name == "autosave"){
  377. o.plugin = new dojox.editor.plugins.AutoSave({
  378. url: ("url" in o.args) ? o.args.url : "",
  379. logResults: ("logResults" in o.args) ? o.args.logResults : true,
  380. interval: ("interval" in o.args) ? o.args.interval : 5
  381. });
  382. }
  383. });
  384. return dojox.editor.plugins.AutoSave;
  385. });