PageRenderTime 25ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/_tools/closure-library/closure/goog/ui/editor/abstractdialog.js

https://github.com/resistorsoftware/box2d
JavaScript | 421 lines | 148 code | 54 blank | 219 comment | 12 complexity | a6c4875dd5944fcaebdccb2c9c56c6cb MD5 | raw file
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Wrapper around {@link goog.ui.Dialog}, to provide
  16. * dialogs that are smarter about interacting with a rich text editor.
  17. *
  18. *
  19. *
  20. *
  21. * @author nicksantos@google.com (Nick Santos)
  22. *
  23. */
  24. goog.provide('goog.ui.editor.AbstractDialog');
  25. goog.provide('goog.ui.editor.AbstractDialog.Builder');
  26. goog.provide('goog.ui.editor.AbstractDialog.EventType');
  27. goog.require('goog.dom');
  28. goog.require('goog.dom.classes');
  29. goog.require('goog.events.EventTarget');
  30. goog.require('goog.ui.Dialog');
  31. goog.require('goog.ui.Dialog.ButtonSet');
  32. goog.require('goog.ui.Dialog.DefaultButtonKeys');
  33. goog.require('goog.ui.Dialog.Event');
  34. goog.require('goog.ui.Dialog.EventType');
  35. // *** Public interface ***************************************************** //
  36. /**
  37. * Creates an object that represents a dialog box.
  38. * @param {goog.dom.DomHelper} domHelper DomHelper to be used to create the
  39. * dialog's dom structure.
  40. * @constructor
  41. * @extends {goog.events.EventTarget}
  42. */
  43. goog.ui.editor.AbstractDialog = function(domHelper) {
  44. goog.events.EventTarget.call(this);
  45. this.dom = domHelper;
  46. };
  47. goog.inherits(goog.ui.editor.AbstractDialog, goog.events.EventTarget);
  48. /**
  49. * Causes the dialog box to appear, centered on the screen. Lazily creates the
  50. * dialog if needed.
  51. */
  52. goog.ui.editor.AbstractDialog.prototype.show = function() {
  53. // Lazily create the wrapped dialog to be shown.
  54. if (!this.dialogInternal_) {
  55. this.dialogInternal_ = this.createDialogControl();
  56. this.dialogInternal_.addEventListener(goog.ui.Dialog.EventType.AFTER_HIDE,
  57. this.handleAfterHide_, false, this);
  58. }
  59. this.dialogInternal_.setVisible(true);
  60. };
  61. /**
  62. * Hides the dialog, causing AFTER_HIDE to fire.
  63. */
  64. goog.ui.editor.AbstractDialog.prototype.hide = function() {
  65. if (this.dialogInternal_) {
  66. // This eventually fires the wrapped dialog's AFTER_HIDE event, calling our
  67. // handleAfterHide_().
  68. this.dialogInternal_.setVisible(false);
  69. }
  70. };
  71. /**
  72. * @return {boolean} Whether the dialog is open.
  73. */
  74. goog.ui.editor.AbstractDialog.prototype.isOpen = function() {
  75. return !!this.dialogInternal_ && this.dialogInternal_.isVisible();
  76. };
  77. /**
  78. * Runs the handler registered on the OK button event and closes the dialog if
  79. * that handler succeeds.
  80. * This is useful in cases such as double-clicking an item in the dialog is
  81. * equivalent to selecting it and clicking the default button.
  82. * @protected
  83. */
  84. goog.ui.editor.AbstractDialog.prototype.processOkAndClose = function() {
  85. // Fake an OK event from the wrapped dialog control.
  86. var evt = new goog.ui.Dialog.Event(goog.ui.Dialog.DefaultButtonKeys.OK, null);
  87. if (this.handleOk(evt)) {
  88. // handleOk calls dispatchEvent, so if any listener calls preventDefault it
  89. // will return false and we won't hide the dialog.
  90. this.hide();
  91. }
  92. };
  93. // *** Dialog events ******************************************************** //
  94. /**
  95. * Event type constants for events the dialog fires.
  96. * @enum {string}
  97. */
  98. goog.ui.editor.AbstractDialog.EventType = {
  99. // This event is fired after the dialog is hidden, no matter if it was closed
  100. // via OK or Cancel or is being disposed without being hidden first.
  101. AFTER_HIDE: 'afterhide',
  102. // Either the cancel or OK events can be canceled via preventDefault or by
  103. // returning false from their handlers to stop the dialog from closing.
  104. CANCEL: 'cancel',
  105. OK: 'ok'
  106. };
  107. // *** Inner helper class *************************************************** //
  108. /**
  109. * A builder class for the dialog control. All methods except build return this.
  110. * @param {goog.ui.editor.AbstractDialog} editorDialog Editor dialog object
  111. * that will wrap the wrapped dialog object this builder will create.
  112. * @constructor
  113. */
  114. goog.ui.editor.AbstractDialog.Builder = function(editorDialog) {
  115. // We require the editor dialog to be passed in so that the builder can set up
  116. // ok/cancel listeners by default, making it easier for most dialogs.
  117. this.editorDialog_ = editorDialog;
  118. this.wrappedDialog_ = new goog.ui.Dialog('', true, this.editorDialog_.dom);
  119. this.buttonSet_ = new goog.ui.Dialog.ButtonSet(this.editorDialog_.dom);
  120. this.buttonHandlers_ = {};
  121. this.addClassName(goog.getCssName('tr-dialog'));
  122. };
  123. /**
  124. * Sets the title of the dialog.
  125. * @param {string} title Title HTML (escaped).
  126. * @return {goog.ui.editor.AbstractDialog.Builder} This.
  127. */
  128. goog.ui.editor.AbstractDialog.Builder.prototype.setTitle = function(title) {
  129. this.wrappedDialog_.setTitle(title);
  130. return this;
  131. };
  132. /**
  133. * Adds an OK button to the dialog. Clicking this button will cause {@link
  134. * handleOk} to run, subsequently dispatching an OK event.
  135. * @param {string=} opt_label The caption for the button, if not "OK".
  136. * @return {goog.ui.editor.AbstractDialog.Builder} This.
  137. */
  138. goog.ui.editor.AbstractDialog.Builder.prototype.addOkButton =
  139. function(opt_label) {
  140. var key = goog.ui.Dialog.DefaultButtonKeys.OK;
  141. /** @desc Label for an OK button in an editor dialog. */
  142. var MSG_TR_DIALOG_OK = goog.getMsg('OK');
  143. // True means this is the default/OK button.
  144. this.buttonSet_.set(key, opt_label || MSG_TR_DIALOG_OK, true);
  145. this.buttonHandlers_[key] = goog.bind(this.editorDialog_.handleOk,
  146. this.editorDialog_);
  147. return this;
  148. };
  149. /**
  150. * Adds a Cancel button to the dialog. Clicking this button will cause {@link
  151. * handleCancel} to run, subsequently dispatching a CANCEL event.
  152. * @param {string=} opt_label The caption for the button, if not "Cancel".
  153. * @return {goog.ui.editor.AbstractDialog.Builder} This.
  154. */
  155. goog.ui.editor.AbstractDialog.Builder.prototype.addCancelButton =
  156. function(opt_label) {
  157. var key = goog.ui.Dialog.DefaultButtonKeys.CANCEL;
  158. /** @desc Label for a cancel button in an editor dialog. */
  159. var MSG_TR_DIALOG_CANCEL = goog.getMsg('Cancel');
  160. // False means it's not the OK button, true means it's the Cancel button.
  161. this.buttonSet_.set(key, opt_label || MSG_TR_DIALOG_CANCEL, false, true);
  162. this.buttonHandlers_[key] = goog.bind(this.editorDialog_.handleCancel,
  163. this.editorDialog_);
  164. return this;
  165. };
  166. /**
  167. * Adds a custom button to the dialog.
  168. * @param {string} label The caption for the button.
  169. * @param {function(goog.ui.Dialog.EventType):*} handler Function called when
  170. * the button is clicked. It is recommended that this function be a method
  171. * in the concrete subclass of AbstractDialog using this Builder, and that
  172. * it dispatch an event (see {@link handleOk}).
  173. * @param {string=} opt_buttonId Identifier to be used to access the button when
  174. * calling AbstractDialog.getButtonElement().
  175. * @return {goog.ui.editor.AbstractDialog.Builder} This.
  176. */
  177. goog.ui.editor.AbstractDialog.Builder.prototype.addButton =
  178. function(label, handler, opt_buttonId) {
  179. // We don't care what the key is, just that we can match the button with the
  180. // handler function later.
  181. var key = opt_buttonId || goog.string.createUniqueString();
  182. this.buttonSet_.set(key, label);
  183. this.buttonHandlers_[key] = handler;
  184. return this;
  185. };
  186. /**
  187. * Puts a CSS class on the dialog's main element.
  188. * @param {string} className The class to add.
  189. * @return {goog.ui.editor.AbstractDialog.Builder} This.
  190. */
  191. goog.ui.editor.AbstractDialog.Builder.prototype.addClassName =
  192. function(className) {
  193. goog.dom.classes.add(this.wrappedDialog_.getDialogElement(), className);
  194. return this;
  195. };
  196. /**
  197. * Sets the content element of the dialog.
  198. * @param {Element} contentElem An element for the main body.
  199. * @return {goog.ui.editor.AbstractDialog.Builder} This.
  200. */
  201. goog.ui.editor.AbstractDialog.Builder.prototype.setContent =
  202. function(contentElem) {
  203. goog.dom.appendChild(this.wrappedDialog_.getContentElement(), contentElem);
  204. return this;
  205. };
  206. /**
  207. * Builds the wrapped dialog control. May only be called once, after which
  208. * no more methods may be called on this builder.
  209. * @return {goog.ui.Dialog} The wrapped dialog control.
  210. */
  211. goog.ui.editor.AbstractDialog.Builder.prototype.build = function() {
  212. if (this.buttonSet_.isEmpty()) {
  213. // If caller didn't set any buttons, add an OK and Cancel button by default.
  214. this.addOkButton();
  215. this.addCancelButton();
  216. }
  217. this.wrappedDialog_.setButtonSet(this.buttonSet_);
  218. var handlers = this.buttonHandlers_;
  219. this.buttonHandlers_ = null;
  220. this.wrappedDialog_.addEventListener(goog.ui.Dialog.EventType.SELECT,
  221. // Listen for the SELECT event, which means a button was clicked, and
  222. // call the handler associated with that button via the key property.
  223. function(e) {
  224. if (handlers[e.key]) {
  225. return handlers[e.key](e);
  226. }
  227. });
  228. // All editor dialogs are modal.
  229. this.wrappedDialog_.setModal(true);
  230. var dialog = this.wrappedDialog_;
  231. this.wrappedDialog_ = null;
  232. return dialog;
  233. };
  234. /**
  235. * Editor dialog that will wrap the wrapped dialog this builder will create.
  236. * @type {goog.ui.editor.AbstractDialog}
  237. * @private
  238. */
  239. goog.ui.editor.AbstractDialog.Builder.prototype.editorDialog_;
  240. /**
  241. * wrapped dialog control being built by this builder.
  242. * @type {goog.ui.Dialog}
  243. * @private
  244. */
  245. goog.ui.editor.AbstractDialog.Builder.prototype.wrappedDialog_;
  246. /**
  247. * Set of buttons to be added to the wrapped dialog control.
  248. * @type {goog.ui.Dialog.ButtonSet}
  249. * @private
  250. */
  251. goog.ui.editor.AbstractDialog.Builder.prototype.buttonSet_;
  252. /**
  253. * Map from keys that will be returned in the wrapped dialog SELECT events to
  254. * handler functions to be called to handle those events.
  255. * @type {Object}
  256. * @private
  257. */
  258. goog.ui.editor.AbstractDialog.Builder.prototype.buttonHandlers_;
  259. // *** Protected interface ************************************************** //
  260. /**
  261. * The DOM helper for the parent document.
  262. * @type {goog.dom.DomHelper}
  263. * @protected
  264. */
  265. goog.ui.editor.AbstractDialog.prototype.dom;
  266. /**
  267. * Creates and returns the goog.ui.Dialog control that is being wrapped
  268. * by this object.
  269. * @return {goog.ui.Dialog} Created Dialog control.
  270. * @protected
  271. */
  272. goog.ui.editor.AbstractDialog.prototype.createDialogControl =
  273. goog.abstractMethod;
  274. /**
  275. * Returns the HTML Button element for the OK button in this dialog.
  276. * @return {Element} The button element if found, else null.
  277. * @protected
  278. */
  279. goog.ui.editor.AbstractDialog.prototype.getOkButtonElement = function() {
  280. return this.getButtonElement(goog.ui.Dialog.DefaultButtonKeys.OK);
  281. };
  282. /**
  283. * Returns the HTML Button element for the Cancel button in this dialog.
  284. * @return {Element} The button element if found, else null.
  285. * @protected
  286. */
  287. goog.ui.editor.AbstractDialog.prototype.getCancelButtonElement = function() {
  288. return this.getButtonElement(goog.ui.Dialog.DefaultButtonKeys.CANCEL);
  289. };
  290. /**
  291. * Returns the HTML Button element for the button added to this dialog with
  292. * the given button id.
  293. * @param {string} buttonId The id of the button to get.
  294. * @return {Element} The button element if found, else null.
  295. * @protected
  296. */
  297. goog.ui.editor.AbstractDialog.prototype.getButtonElement = function(buttonId) {
  298. return this.dialogInternal_.getButtonSet().getButton(buttonId);
  299. };
  300. /**
  301. * Creates and returns the event object to be used when dispatching the OK
  302. * event to listeners, or returns null to prevent the dialog from closing.
  303. * Subclasses should override this to return their own subclass of
  304. * goog.events.Event that includes all data a plugin would need from the dialog.
  305. * @param {goog.events.Event} e The event object dispatched by the wrapped
  306. * dialog.
  307. * @return {goog.events.Event} The event object to be used when dispatching the
  308. * OK event to listeners.
  309. * @protected
  310. */
  311. goog.ui.editor.AbstractDialog.prototype.createOkEvent = goog.abstractMethod;
  312. /**
  313. * Handles the event dispatched by the wrapped dialog control when the user
  314. * clicks the OK button. Attempts to create the OK event object and dispatches
  315. * it if successful.
  316. * @param {goog.ui.Dialog.Event} e wrapped dialog OK event object.
  317. * @return {boolean} Whether the default action (closing the dialog) should
  318. * still be executed. This will be false if the OK event could not be
  319. * created to be dispatched, or if any listener to that event returs false
  320. * or calls preventDefault.
  321. * @protected
  322. */
  323. goog.ui.editor.AbstractDialog.prototype.handleOk = function(e) {
  324. var eventObj = this.createOkEvent(e);
  325. if (eventObj) {
  326. return this.dispatchEvent(eventObj);
  327. } else {
  328. return false;
  329. }
  330. };
  331. /**
  332. * Handles the event dispatched by the wrapped dialog control when the user
  333. * clicks the Cancel button. Simply dispatches a CANCEL event.
  334. * @protected
  335. */
  336. goog.ui.editor.AbstractDialog.prototype.handleCancel = function() {
  337. this.dispatchEvent(goog.ui.editor.AbstractDialog.EventType.CANCEL);
  338. };
  339. /**
  340. * Disposes of the dialog. If the dialog is open, it will be hidden and
  341. * AFTER_HIDE will be dispatched.
  342. * @override
  343. * @protected
  344. */
  345. goog.ui.editor.AbstractDialog.prototype.disposeInternal = function() {
  346. if (this.dialogInternal_) {
  347. this.hide();
  348. this.dialogInternal_.dispose();
  349. this.dialogInternal_ = null;
  350. }
  351. goog.ui.editor.AbstractDialog.superClass_.disposeInternal.call(this);
  352. };
  353. // *** Private implementation *********************************************** //
  354. /**
  355. * The wrapped dialog widget.
  356. * @type {goog.ui.Dialog}
  357. * @private
  358. */
  359. goog.ui.editor.AbstractDialog.prototype.dialogInternal_;
  360. /**
  361. * Cleans up after the dialog is hidden and fires the AFTER_HIDE event. Should
  362. * be a listener for the wrapped dialog's AFTER_HIDE event.
  363. * @private
  364. */
  365. goog.ui.editor.AbstractDialog.prototype.handleAfterHide_ = function() {
  366. this.dispatchEvent(goog.ui.editor.AbstractDialog.EventType.AFTER_HIDE);
  367. };