InlineEditBox.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. if (!dojo._hasResource["dijit.form.InlineEditBox"]) { // _hasResource checks
  2. // added by build. Do
  3. // not use _hasResource
  4. // directly in your
  5. // code.
  6. dojo._hasResource["dijit.form.InlineEditBox"] = true;
  7. dojo.provide("dijit.form.InlineEditBox");
  8. dojo.require("dojo.i18n");
  9. dojo.require("dijit.form._FormWidget");
  10. dojo.require("dijit._Container");
  11. dojo.require("dijit.form.Button");
  12. dojo.requireLocalization("dijit", "common", null,
  13. "ko,zh,ja,zh-tw,ru,it,hu,fr,pt,ROOT,pl,es,de,cs");
  14. dojo
  15. .deprecated(
  16. "dijit.form.InlineEditBox is deprecated, use dijit.InlineEditBox instead",
  17. "", "1.1");
  18. dojo.declare("dijit.form.InlineEditBox", [dijit.form._FormWidget,
  19. dijit._Container],
  20. // summary
  21. // Wrapper widget to a text edit widget.
  22. // The text is displayed on the page using normal user-styling.
  23. // When clicked, the text is hidden, and the edit widget is
  24. // visible, allowing the text to be updated. Optionally,
  25. // Save and Cancel button are displayed below the edit widget.
  26. // When Save is clicked, the text is pulled from the edit
  27. // widget and redisplayed and the edit widget is again hidden.
  28. // Currently all textboxes that inherit from dijit.form.TextBox
  29. // are supported edit widgets.
  30. // An edit widget must support the following API to be used:
  31. // String getDisplayedValue() OR String getValue()
  32. // void setDisplayedValue(String) OR void setValue(String)
  33. // void focus()
  34. // It must also be able to initialize with style="display:none;"
  35. // set.
  36. {
  37. templateString : "<span\n\t><fieldset dojoAttachPoint=\"editNode\" style=\"display:none;\" waiRole=\"presentation\"\n\t\t><div dojoAttachPoint=\"containerNode\" dojoAttachEvent=\"onkeypress:_onEditWidgetKeyPress\"></div\n\t\t><div dojoAttachPoint=\"buttonContainer\"\n\t\t\t><button class='saveButton' dojoAttachPoint=\"saveButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:save\">${buttonSave}</button\n\t\t\t><button class='cancelButton' dojoAttachPoint=\"cancelButton\" dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:cancel\">${buttonCancel}</button\n\t\t></div\n\t></fieldset\n\t><span tabIndex=\"0\" dojoAttachPoint=\"textNode,focusNode\" waiRole=\"button\" style=\"display:none;\"\n\t\tdojoAttachEvent=\"onkeypress:_onKeyPress,onclick:_onClick,onmouseout:_onMouseOut,onmouseover:_onMouseOver,onfocus:_onMouseOver,onblur:_onMouseOut\"\n\t></span\n></span>\n",
  38. // editing: Boolean
  39. // Is the node currently in edit mode?
  40. editing : false,
  41. // autoSave: Boolean
  42. // Changing the value automatically saves it, don't have to push
  43. // save button
  44. autoSave : true,
  45. // buttonSave: String
  46. // Save button label
  47. buttonSave : "",
  48. // buttonCancel: String
  49. // Cancel button label
  50. buttonCancel : "",
  51. // renderAsHtml: Boolean
  52. // should text render as HTML(true) or plain text(false)
  53. renderAsHtml : false,
  54. widgetsInTemplate : true,
  55. // _display: String
  56. // srcNodeRef display style
  57. _display : "",
  58. startup : function() {
  59. // look for the input widget as a child of the containerNode
  60. if (!this._started) {
  61. if (this.editWidget) {
  62. this.containerNode
  63. .appendChild(this.editWidget.domNode);
  64. } else {
  65. this.editWidget = this.getChildren()[0];
  66. }
  67. // #3209: copy the style from the source
  68. // don't copy ALL properties though, just the
  69. // necessary/applicable ones
  70. var srcStyle = dojo.getComputedStyle(this.domNode);
  71. dojo.forEach(["fontWeight", "fontFamily", "fontSize",
  72. "fontStyle"], function(prop) {
  73. this.editWidget.focusNode.style[prop] = srcStyle[prop];
  74. }, this);
  75. this._setEditValue = dojo.hitch(this.editWidget,
  76. this.editWidget.setDisplayedValue
  77. || this.editWidget.setValue);
  78. this._getEditValue = dojo.hitch(this.editWidget,
  79. this.editWidget.getDisplayedValue
  80. || this.editWidget.getValue);
  81. this._setEditFocus = dojo.hitch(this.editWidget,
  82. this.editWidget.focus);
  83. this._isEditValid = dojo.hitch(this.editWidget,
  84. this.editWidget.isValid || function() {
  85. return true;
  86. });
  87. this.editWidget.onChange = dojo
  88. .hitch(this, "_onChange");
  89. if (!this.autoSave) { // take over the setValue method
  90. // so we can know when the value
  91. // changes
  92. this._oldSetValue = this.editWidget.setValue;
  93. var _this = this;
  94. this.editWidget.setValue = dojo.hitch(this,
  95. function(value) {
  96. _this._oldSetValue.apply(
  97. _this.editWidget, arguments);
  98. _this._onEditWidgetKeyPress(null); // check
  99. // the
  100. // Save
  101. // button
  102. });
  103. }
  104. this._showText();
  105. this._started = true;
  106. }
  107. },
  108. postMixInProperties : function() {
  109. this._srcTag = this.srcNodeRef.tagName;
  110. this._srcStyle = dojo.getComputedStyle(this.srcNodeRef);
  111. // getComputedStyle is not good until after onLoad is called
  112. var srcNodeStyle = this.srcNodeRef.style;
  113. this._display = "";
  114. if (srcNodeStyle && srcNodeStyle.display) {
  115. this._display = srcNodeStyle.display;
  116. } else {
  117. switch (this.srcNodeRef.tagName.toLowerCase()) {
  118. case 'span' :
  119. case 'input' :
  120. case 'img' :
  121. case 'button' :
  122. this._display = 'inline';
  123. break;
  124. default :
  125. this._display = 'block';
  126. break;
  127. }
  128. }
  129. this.inherited('postMixInProperties', arguments);
  130. this.messages = dojo.i18n.getLocalization("dijit",
  131. "common", this.lang);
  132. dojo.forEach(["buttonSave", "buttonCancel"],
  133. function(prop) {
  134. if (!this[prop]) {
  135. this[prop] = this.messages[prop];
  136. }
  137. }, this);
  138. },
  139. postCreate : function() {
  140. // don't call setValue yet since the editing widget is not
  141. // setup
  142. if (this.autoSave) {
  143. dojo.style(this.buttonContainer, "display", "none");
  144. }
  145. },
  146. _onKeyPress : function(e) {
  147. // summary: handle keypress when edit box is not open
  148. if (this.disabled || e.altKey || e.ctrlKey) {
  149. return;
  150. }
  151. if (e.charCode == dojo.keys.SPACE
  152. || e.keyCode == dojo.keys.ENTER) {
  153. dojo.stopEvent(e);
  154. this._onClick(e);
  155. }
  156. },
  157. _onMouseOver : function() {
  158. if (!this.editing) {
  159. var classname = this.disabled
  160. ? "dijitDisabledClickableRegion"
  161. : "dijitClickableRegion";
  162. dojo.addClass(this.textNode, classname);
  163. }
  164. },
  165. _onMouseOut : function() {
  166. if (!this.editing) {
  167. var classStr = this.disabled
  168. ? "dijitDisabledClickableRegion"
  169. : "dijitClickableRegion";
  170. dojo.removeClass(this.textNode, classStr);
  171. }
  172. },
  173. _onClick : function(e) {
  174. // summary
  175. // When user clicks the text, then start editing.
  176. // Hide the text and display the form instead.
  177. if (this.editing || this.disabled) {
  178. return;
  179. }
  180. this._onMouseOut();
  181. this.editing = true;
  182. // show the edit form and hide the read only version of the
  183. // text
  184. this._setEditValue(this._isEmpty ? '' : (this.renderAsHtml
  185. ? this.textNode.innerHTML
  186. : this.textNode.innerHTML.replace(/\s*\r?\n\s*/g,
  187. "").replace(/<br\/?>/gi, "\n").replace(
  188. /&gt;/g, ">").replace(/&lt;/g, "<")
  189. .replace(/&amp;/g, "&")));
  190. this._initialText = this._getEditValue();
  191. this._visualize();
  192. // Before changing the focus, give the browser time to
  193. // render.
  194. setTimeout(dojo.hitch(this, function() {
  195. this._setEditFocus();
  196. this.saveButton.setDisabled(true);
  197. }), 1);
  198. },
  199. _visualize : function() {
  200. dojo.style(this.editNode, "display", this.editing
  201. ? this._display
  202. : "none");
  203. // #3749: try to set focus now to fix missing caret
  204. // #3997: call right after this.containerNode appears
  205. if (this.editing) {
  206. this._setEditFocus();
  207. }
  208. dojo.style(this.textNode, "display", this.editing
  209. ? "none"
  210. : this._display);
  211. },
  212. _showText : function() {
  213. var value = "" + this._getEditValue(); // "" is to make
  214. // sure its a string
  215. dijit.form.InlineEditBox.superclass.setValue.call(this,
  216. value);
  217. // whitespace is really hard to click so show a ?
  218. // TODO: show user defined message in gray
  219. if (/^\s*$/.test(value)) {
  220. value = "?";
  221. this._isEmpty = true;
  222. } else {
  223. this._isEmpty = false;
  224. }
  225. if (this.renderAsHtml) {
  226. this.textNode.innerHTML = value;
  227. } else {
  228. this.textNode.innerHTML = "";
  229. if (value.split) {
  230. var _this = this;
  231. var isFirst = true;
  232. dojo.forEach(value.split("\n"), function(line) {
  233. if (isFirst) {
  234. isFirst = false;
  235. } else {
  236. _this.textNode.appendChild(document
  237. .createElement("BR")); // preserve
  238. // line
  239. // breaks
  240. }
  241. _this.textNode.appendChild(document
  242. .createTextNode(line)); // use
  243. // text
  244. // nodes
  245. // so
  246. // that
  247. // imbedded
  248. // tags
  249. // can
  250. // be
  251. // edited
  252. });
  253. } else {
  254. this.textNode.appendChild(document
  255. .createTextNode(value));
  256. }
  257. }
  258. this._visualize();
  259. },
  260. save : function(e) {
  261. // summary: Callback when user presses "Save" button or it's
  262. // simulated.
  263. // e is passed in if click on save button or user presses
  264. // Enter. It's not
  265. // passed in when called by _onBlur.
  266. if (typeof e == "object") {
  267. dojo.stopEvent(e);
  268. }
  269. if (!this.enableSave()) {
  270. return;
  271. }
  272. this.editing = false;
  273. this._showText();
  274. // If save button pressed on non-autoSave widget or Enter
  275. // pressed on autoSave
  276. // widget, restore focus to the inline text.
  277. if (e) {
  278. dijit.focus(this.focusNode);
  279. }
  280. if (this._lastValue != this._lastValueReported) {
  281. this.onChange(this._lastValue); // tell the world that
  282. // we have changed
  283. }
  284. },
  285. cancel : function(e) {
  286. // summary: Callback when user presses "Cancel" button or
  287. // it's simulated.
  288. // e is passed in if click on cancel button or user presses
  289. // Esc. It's not
  290. // passed in when called by _onBlur.
  291. if (e) {
  292. dojo.stopEvent(e);
  293. }
  294. this.editing = false;
  295. this._visualize();
  296. // If cancel button pressed on non-autoSave widget or Esc
  297. // pressed on autoSave
  298. // widget, restore focus to the inline text.
  299. if (e) {
  300. dijit.focus(this.focusNode);
  301. }
  302. },
  303. setValue : function(/* String */value) {
  304. // sets the text without informing the server
  305. this._setEditValue(value);
  306. this.editing = false;
  307. this._showText();
  308. },
  309. _onEditWidgetKeyPress : function(e) {
  310. // summary:
  311. // Callback when keypress in the edit box (see template).
  312. // For autoSave widgets, if Esc/Enter, call cancel/save.
  313. // For non-autoSave widgets, enable save button if the text
  314. // value is
  315. // different than the original value.
  316. if (!this.editing) {
  317. return;
  318. }
  319. if (this.autoSave) {
  320. // If Enter/Esc pressed, treat as save/cancel.
  321. if (e.keyCode == dojo.keys.ESCAPE) {
  322. this.cancel(e);
  323. } else if (e.keyCode == dojo.keys.ENTER) {
  324. this.save(e);
  325. }
  326. } else {
  327. var _this = this;
  328. // Delay before calling _getEditValue.
  329. // The delay gives the browser a chance to update the
  330. // textarea.
  331. setTimeout(function() {
  332. _this.saveButton
  333. .setDisabled(_this._getEditValue() == _this._initialText);
  334. }, 100);
  335. }
  336. },
  337. _onBlur : function() {
  338. // summary:
  339. // Called by the focus manager in focus.js when focus moves
  340. // outside of the
  341. // InlineEditBox widget (or it's descendants).
  342. if (this.autoSave && this.editing) {
  343. if (this._getEditValue() == this._initialText) {
  344. this.cancel();
  345. } else {
  346. this.save();
  347. }
  348. }
  349. },
  350. enableSave : function() {
  351. // summary: User replacable function returning a Boolean to
  352. // indicate
  353. // if the Save button should be enabled or not - usually due
  354. // to invalid conditions
  355. return this._isEditValid();
  356. },
  357. _onChange : function() {
  358. // summary:
  359. // This is called when the underlying widget fires an
  360. // onChange event,
  361. // which means that the user has finished entering the value
  362. if (!this.editing) {
  363. this._showText(); // asynchronous update made famous
  364. // by ComboBox/FilteringSelect
  365. } else if (this.autoSave) {
  366. this.save(1);
  367. } else {
  368. // #3752
  369. // if the keypress does not bubble up to the div,
  370. // (iframe in TextArea blocks it for example)
  371. // make sure the save button gets enabled
  372. this.saveButton
  373. .setDisabled((this._getEditValue() == this._initialText)
  374. || !this.enableSave());
  375. }
  376. },
  377. setDisabled : function(/* Boolean */disabled) {
  378. this.saveButton.setDisabled(disabled);
  379. this.cancelButton.setDisabled(disabled);
  380. this.textNode.disabled = disabled;
  381. this.editWidget.setDisabled(disabled);
  382. this.inherited('setDisabled', arguments);
  383. }
  384. });
  385. }