popupdatepicker.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright 2007 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 Popup Date Picker implementation. Pairs a goog.ui.DatePicker
  16. * with a goog.ui.Popup allowing the DatePicker to be attached to elements.
  17. *
  18. * @see ../demos/popupdatepicker.html
  19. */
  20. goog.provide('goog.ui.PopupDatePicker');
  21. goog.require('goog.events.EventType');
  22. goog.require('goog.positioning.AnchoredPosition');
  23. goog.require('goog.positioning.Corner');
  24. goog.require('goog.positioning.Overflow');
  25. goog.require('goog.style');
  26. goog.require('goog.ui.Component');
  27. goog.require('goog.ui.DatePicker');
  28. goog.require('goog.ui.Popup');
  29. goog.require('goog.ui.PopupBase');
  30. /**
  31. * Popup date picker widget. Fires goog.ui.PopupBase.EventType.SHOW or HIDE
  32. * events when its visibility changes.
  33. *
  34. * @param {goog.ui.DatePicker=} opt_datePicker Optional DatePicker. This
  35. * enables the use of a custom date-picker instance.
  36. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
  37. * @extends {goog.ui.Component}
  38. * @constructor
  39. */
  40. goog.ui.PopupDatePicker = function(opt_datePicker, opt_domHelper) {
  41. goog.ui.Component.call(this, opt_domHelper);
  42. this.datePicker_ = opt_datePicker || new goog.ui.DatePicker();
  43. };
  44. goog.inherits(goog.ui.PopupDatePicker, goog.ui.Component);
  45. goog.tagUnsealableClass(goog.ui.PopupDatePicker);
  46. /**
  47. * Instance of a date picker control.
  48. * @type {goog.ui.DatePicker?}
  49. * @private
  50. */
  51. goog.ui.PopupDatePicker.prototype.datePicker_ = null;
  52. /**
  53. * Instance of goog.ui.Popup used to manage the behavior of the date picker.
  54. * @type {goog.ui.Popup?}
  55. * @private
  56. */
  57. goog.ui.PopupDatePicker.prototype.popup_ = null;
  58. /**
  59. * Reference to the element that triggered the last popup.
  60. * @type {Element}
  61. * @private
  62. */
  63. goog.ui.PopupDatePicker.prototype.lastTarget_ = null;
  64. /**
  65. * Whether the date picker can move the focus to its key event target when it
  66. * is shown. The default is true. Setting to false can break keyboard
  67. * navigation, but this is needed for certain scenarios, for example the
  68. * toolbar menu in trogedit which can't have the selection changed.
  69. * @type {boolean}
  70. * @private
  71. */
  72. goog.ui.PopupDatePicker.prototype.allowAutoFocus_ = true;
  73. /** @override */
  74. goog.ui.PopupDatePicker.prototype.createDom = function() {
  75. goog.ui.PopupDatePicker.superClass_.createDom.call(this);
  76. this.getElement().className = goog.getCssName('goog-popupdatepicker');
  77. this.popup_ = new goog.ui.Popup(this.getElement());
  78. this.popup_.setParentEventTarget(this);
  79. };
  80. /**
  81. * @return {boolean} Whether the date picker is visible.
  82. */
  83. goog.ui.PopupDatePicker.prototype.isVisible = function() {
  84. return this.popup_ ? this.popup_.isVisible() : false;
  85. };
  86. /** @override */
  87. goog.ui.PopupDatePicker.prototype.enterDocument = function() {
  88. goog.ui.PopupDatePicker.superClass_.enterDocument.call(this);
  89. // Create the DatePicker, if it isn't already.
  90. // Done here as DatePicker assumes that the element passed to it is attached
  91. // to a document.
  92. if (!this.datePicker_.isInDocument()) {
  93. var el = this.getElement();
  94. // Make it initially invisible
  95. el.style.visibility = 'hidden';
  96. goog.style.setElementShown(el, false);
  97. this.datePicker_.decorate(el);
  98. }
  99. this.getHandler()
  100. .listen(
  101. this.datePicker_, goog.ui.DatePicker.Events.CHANGE,
  102. this.onDateChanged_)
  103. .listen(
  104. this.datePicker_, goog.ui.DatePicker.Events.SELECT,
  105. this.onDateSelected_);
  106. };
  107. /** @override */
  108. goog.ui.PopupDatePicker.prototype.disposeInternal = function() {
  109. goog.ui.PopupDatePicker.superClass_.disposeInternal.call(this);
  110. if (this.popup_) {
  111. this.popup_.dispose();
  112. this.popup_ = null;
  113. }
  114. this.datePicker_.dispose();
  115. this.datePicker_ = null;
  116. this.lastTarget_ = null;
  117. };
  118. /**
  119. * DatePicker cannot be used to decorate pre-existing html, since they're
  120. * not based on Components.
  121. * @param {Element} element Element to decorate.
  122. * @return {boolean} Returns always false.
  123. * @override
  124. */
  125. goog.ui.PopupDatePicker.prototype.canDecorate = function(element) {
  126. return false;
  127. };
  128. /**
  129. * @return {goog.ui.DatePicker} The date picker instance.
  130. */
  131. goog.ui.PopupDatePicker.prototype.getDatePicker = function() {
  132. return this.datePicker_;
  133. };
  134. /**
  135. * @return {goog.date.Date?} The selected date, if any. See
  136. * goog.ui.DatePicker.getDate().
  137. */
  138. goog.ui.PopupDatePicker.prototype.getDate = function() {
  139. return this.datePicker_.getDate();
  140. };
  141. /**
  142. * Sets the selected date. See goog.ui.DatePicker.setDate().
  143. * @param {goog.date.Date?} date The date to select.
  144. */
  145. goog.ui.PopupDatePicker.prototype.setDate = function(date) {
  146. this.datePicker_.setDate(date);
  147. };
  148. /**
  149. * @return {Element} The last element that triggered the popup.
  150. */
  151. goog.ui.PopupDatePicker.prototype.getLastTarget = function() {
  152. return this.lastTarget_;
  153. };
  154. /**
  155. * Attaches the popup date picker to an element.
  156. * @param {Element} element The element to attach to.
  157. */
  158. goog.ui.PopupDatePicker.prototype.attach = function(element) {
  159. this.getHandler().listen(
  160. element, goog.events.EventType.MOUSEDOWN, this.showPopup_);
  161. };
  162. /**
  163. * Detatches the popup date picker from an element.
  164. * @param {Element} element The element to detach from.
  165. */
  166. goog.ui.PopupDatePicker.prototype.detach = function(element) {
  167. this.getHandler().unlisten(
  168. element, goog.events.EventType.MOUSEDOWN, this.showPopup_);
  169. };
  170. /**
  171. * Sets whether the date picker can automatically move focus to its key event
  172. * target when it is set to visible.
  173. * @param {boolean} allow Whether to allow auto focus.
  174. */
  175. goog.ui.PopupDatePicker.prototype.setAllowAutoFocus = function(allow) {
  176. this.allowAutoFocus_ = allow;
  177. };
  178. /**
  179. * @return {boolean} Whether the date picker can automatically move focus to
  180. * its key event target when it is set to visible.
  181. */
  182. goog.ui.PopupDatePicker.prototype.getAllowAutoFocus = function() {
  183. return this.allowAutoFocus_;
  184. };
  185. /**
  186. * Show the popup at the bottom-left corner of the specified element.
  187. * @param {Element} element Reference element for displaying the popup -- popup
  188. * will appear at the bottom-left corner of this element.
  189. * @param {boolean=} opt_keepDate Whether to keep the date picker's current
  190. * date. If false, the date is set to null. Defaults to false.
  191. */
  192. goog.ui.PopupDatePicker.prototype.showPopup = function(element, opt_keepDate) {
  193. this.lastTarget_ = element;
  194. this.popup_.setPosition(
  195. new goog.positioning.AnchoredPosition(
  196. element, goog.positioning.Corner.BOTTOM_START,
  197. (goog.positioning.Overflow.ADJUST_X_EXCEPT_OFFSCREEN |
  198. goog.positioning.Overflow.ADJUST_Y_EXCEPT_OFFSCREEN)));
  199. // Don't listen to date changes while we're setting up the popup so we don't
  200. // have to worry about change events when we call setDate().
  201. this.getHandler()
  202. .unlisten(
  203. this.datePicker_, goog.ui.DatePicker.Events.CHANGE,
  204. this.onDateChanged_)
  205. .unlisten(
  206. this.datePicker_, goog.ui.DatePicker.Events.SELECT,
  207. this.onDateSelected_);
  208. var keepDate = !!opt_keepDate;
  209. if (!keepDate) {
  210. this.datePicker_.setDate(null);
  211. }
  212. // Forward the change event onto our listeners. Done before we start
  213. // listening to date changes again, so that listeners can change the date
  214. // without firing more events.
  215. this.dispatchEvent(goog.ui.PopupBase.EventType.SHOW);
  216. this.popup_.setVisible(true);
  217. if (this.allowAutoFocus_) {
  218. this.getElement().focus(); // Our element contains the date picker.
  219. }
  220. this.getHandler()
  221. .listen(
  222. this.datePicker_, goog.ui.DatePicker.Events.CHANGE,
  223. this.onDateChanged_)
  224. .listen(
  225. this.datePicker_, goog.ui.DatePicker.Events.SELECT,
  226. this.onDateSelected_);
  227. };
  228. /**
  229. * Handles click events on the targets and shows the date picker.
  230. * @param {goog.events.Event} event The click event.
  231. * @private
  232. */
  233. goog.ui.PopupDatePicker.prototype.showPopup_ = function(event) {
  234. this.showPopup(/** @type {Element} */ (event.currentTarget));
  235. };
  236. /**
  237. * Hides this popup.
  238. */
  239. goog.ui.PopupDatePicker.prototype.hidePopup = function() {
  240. this.popup_.setVisible(false);
  241. if (this.allowAutoFocus_ && this.lastTarget_) {
  242. this.lastTarget_.focus();
  243. }
  244. };
  245. /**
  246. * Called when date selection is made.
  247. *
  248. * @param {!goog.events.Event} event The date change event.
  249. * @private
  250. */
  251. goog.ui.PopupDatePicker.prototype.onDateSelected_ = function(event) {
  252. this.hidePopup();
  253. // Forward the change event onto our listeners.
  254. this.dispatchEvent(event);
  255. };
  256. /**
  257. * Called when the date is changed.
  258. *
  259. * @param {!goog.events.Event} event The date change event.
  260. * @private
  261. */
  262. goog.ui.PopupDatePicker.prototype.onDateChanged_ = function(event) {
  263. // Forward the change event onto our listeners.
  264. this.dispatchEvent(event);
  265. };