Time3.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-form-field-Time'>/**
  19. </span> * Provides a time input field with a time dropdown and automatic time validation.
  20. *
  21. * This field recognizes and uses JavaScript Date objects as its main {@link #value} type (only the time portion of the
  22. * date is used; the month/day/year are ignored). In addition, it recognizes string values which are parsed according to
  23. * the {@link #format} and/or {@link #altFormats} configs. These may be reconfigured to use time formats appropriate for
  24. * the user's locale.
  25. *
  26. * The field may be limited to a certain range of times by using the {@link #minValue} and {@link #maxValue} configs,
  27. * and the interval between time options in the dropdown can be changed with the {@link #increment} config.
  28. *
  29. * Example usage:
  30. *
  31. * @example
  32. * Ext.create('Ext.form.Panel', {
  33. * title: 'Time Card',
  34. * width: 300,
  35. * bodyPadding: 10,
  36. * renderTo: Ext.getBody(),
  37. * items: [{
  38. * xtype: 'timefield',
  39. * name: 'in',
  40. * fieldLabel: 'Time In',
  41. * minValue: '6:00 AM',
  42. * maxValue: '8:00 PM',
  43. * increment: 30,
  44. * anchor: '100%'
  45. * }, {
  46. * xtype: 'timefield',
  47. * name: 'out',
  48. * fieldLabel: 'Time Out',
  49. * minValue: '6:00 AM',
  50. * maxValue: '8:00 PM',
  51. * increment: 30,
  52. * anchor: '100%'
  53. * }]
  54. * });
  55. */
  56. Ext.define('Ext.form.field.Time', {
  57. extend:'Ext.form.field.ComboBox',
  58. alias: 'widget.timefield',
  59. requires: ['Ext.form.field.Date', 'Ext.picker.Time', 'Ext.view.BoundListKeyNav', 'Ext.Date'],
  60. alternateClassName: ['Ext.form.TimeField', 'Ext.form.Time'],
  61. <span id='Ext-form-field-Time-cfg-triggerCls'> /**
  62. </span> * @cfg {String} [triggerCls='x-form-time-trigger']
  63. * An additional CSS class used to style the trigger button. The trigger will always get the {@link #triggerBaseCls}
  64. * by default and triggerCls will be **appended** if specified.
  65. */
  66. triggerCls: Ext.baseCSSPrefix + 'form-time-trigger',
  67. <span id='Ext-form-field-Time-cfg-minValue'> /**
  68. </span> * @cfg {Date/String} minValue
  69. * The minimum allowed time. Can be either a Javascript date object with a valid time value or a string time in a
  70. * valid format -- see {@link #format} and {@link #altFormats}.
  71. */
  72. <span id='Ext-form-field-Time-cfg-maxValue'> /**
  73. </span> * @cfg {Date/String} maxValue
  74. * The maximum allowed time. Can be either a Javascript date object with a valid time value or a string time in a
  75. * valid format -- see {@link #format} and {@link #altFormats}.
  76. */
  77. //&lt;locale&gt;
  78. <span id='Ext-form-field-Time-cfg-minText'> /**
  79. </span> * @cfg {String} minText
  80. * The error text to display when the entered time is before {@link #minValue}.
  81. */
  82. minText : &quot;The time in this field must be equal to or after {0}&quot;,
  83. //&lt;/locale&gt;
  84. //&lt;locale&gt;
  85. <span id='Ext-form-field-Time-cfg-maxText'> /**
  86. </span> * @cfg {String} maxText
  87. * The error text to display when the entered time is after {@link #maxValue}.
  88. */
  89. maxText : &quot;The time in this field must be equal to or before {0}&quot;,
  90. //&lt;/locale&gt;
  91. //&lt;locale&gt;
  92. <span id='Ext-form-field-Time-cfg-invalidText'> /**
  93. </span> * @cfg {String} invalidText
  94. * The error text to display when the time in the field is invalid.
  95. */
  96. invalidText : &quot;{0} is not a valid time&quot;,
  97. //&lt;/locale&gt;
  98. //&lt;locale&gt;
  99. <span id='Ext-form-field-Time-cfg-format'> /**
  100. </span> * @cfg {String} [format=undefined]
  101. * The default time format string which can be overriden for localization support. The format must be valid
  102. * according to {@link Ext.Date#parse}.
  103. *
  104. * Defaults to `'g:i A'`, e.g., `'3:15 PM'`. For 24-hour time format try `'H:i'` instead.
  105. */
  106. format : &quot;g:i A&quot;,
  107. //&lt;/locale&gt;
  108. //&lt;locale&gt;
  109. <span id='Ext-form-field-Time-cfg-submitFormat'> /**
  110. </span> * @cfg {String} [submitFormat=undefined]
  111. * The date format string which will be submitted to the server. The format must be valid according to
  112. * {@link Ext.Date#parse}.
  113. *
  114. * Defaults to {@link #format}.
  115. */
  116. //&lt;/locale&gt;
  117. //&lt;locale&gt;
  118. <span id='Ext-form-field-Time-cfg-altFormats'> /**
  119. </span> * @cfg {String} altFormats
  120. * Multiple date formats separated by &quot;|&quot; to try when parsing a user input value and it doesn't match the defined
  121. * format.
  122. */
  123. altFormats : &quot;g:ia|g:iA|g:i a|g:i A|h:i|g:i|H:i|ga|ha|gA|h a|g a|g A|gi|hi|gia|hia|g|H|gi a|hi a|giA|hiA|gi A|hi A&quot;,
  124. //&lt;/locale&gt;
  125. <span id='Ext-form-field-Time-cfg-increment'> /**
  126. </span> * @cfg {Number} increment
  127. * The number of minutes between each time value in the list.
  128. */
  129. increment: 15,
  130. <span id='Ext-form-field-Time-cfg-pickerMaxHeight'> /**
  131. </span> * @cfg {Number} pickerMaxHeight
  132. * The maximum height of the {@link Ext.picker.Time} dropdown.
  133. */
  134. pickerMaxHeight: 300,
  135. <span id='Ext-form-field-Time-cfg-selectOnTab'> /**
  136. </span> * @cfg {Boolean} selectOnTab
  137. * Whether the Tab key should select the currently highlighted item.
  138. */
  139. selectOnTab: true,
  140. <span id='Ext-form-field-Time-cfg-snapToIncrement'> /**
  141. </span> * @cfg {Boolean} [snapToIncrement=false]
  142. * Specify as `true` to enforce that only values on the {@link #increment} boundary are accepted.
  143. */
  144. snapToIncrement: false,
  145. <span id='Ext-form-field-Time-property-initDate'> /**
  146. </span> * @private
  147. * This is the date to use when generating time values in the absence of either minValue
  148. * or maxValue. Using the current date causes DST issues on DST boundary dates, so this is an
  149. * arbitrary &quot;safe&quot; date that can be any date aside from DST boundary dates.
  150. */
  151. initDate: '1/1/2008',
  152. initDateFormat: 'j/n/Y',
  153. ignoreSelection: 0,
  154. queryMode: 'local',
  155. displayField: 'disp',
  156. valueField: 'date',
  157. initComponent: function() {
  158. var me = this,
  159. min = me.minValue,
  160. max = me.maxValue;
  161. if (min) {
  162. me.setMinValue(min);
  163. }
  164. if (max) {
  165. me.setMaxValue(max);
  166. }
  167. me.displayTpl = new Ext.XTemplate(
  168. '&lt;tpl for=&quot;.&quot;&gt;' +
  169. '{[typeof values === &quot;string&quot; ? values : this.formatDate(values[&quot;' + me.displayField + '&quot;])]}' +
  170. '&lt;tpl if=&quot;xindex &lt; xcount&quot;&gt;' + me.delimiter + '&lt;/tpl&gt;' +
  171. '&lt;/tpl&gt;', {
  172. formatDate: Ext.Function.bind(me.formatDate, me)
  173. });
  174. this.callParent();
  175. },
  176. <span id='Ext-form-field-Time-method-transformOriginalValue'> /**
  177. </span> * @private
  178. */
  179. transformOriginalValue: function(value) {
  180. if (Ext.isString(value)) {
  181. return this.rawToValue(value);
  182. }
  183. return value;
  184. },
  185. <span id='Ext-form-field-Time-method-isEqual'> /**
  186. </span> * @private
  187. */
  188. isEqual: function(v1, v2) {
  189. return Ext.Date.isEqual(v1, v2);
  190. },
  191. <span id='Ext-form-field-Time-method-setMinValue'> /**
  192. </span> * Replaces any existing {@link #minValue} with the new time and refreshes the picker's range.
  193. * @param {Date/String} value The minimum time that can be selected
  194. */
  195. setMinValue: function(value) {
  196. var me = this,
  197. picker = me.picker;
  198. me.setLimit(value, true);
  199. if (picker) {
  200. picker.setMinValue(me.minValue);
  201. }
  202. },
  203. <span id='Ext-form-field-Time-method-setMaxValue'> /**
  204. </span> * Replaces any existing {@link #maxValue} with the new time and refreshes the picker's range.
  205. * @param {Date/String} value The maximum time that can be selected
  206. */
  207. setMaxValue: function(value) {
  208. var me = this,
  209. picker = me.picker;
  210. me.setLimit(value, false);
  211. if (picker) {
  212. picker.setMaxValue(me.maxValue);
  213. }
  214. },
  215. <span id='Ext-form-field-Time-method-setLimit'> /**
  216. </span> * @private
  217. * Updates either the min or max value. Converts the user's value into a Date object whose
  218. * year/month/day is set to the {@link #initDate} so that only the time fields are significant.
  219. */
  220. setLimit: function(value, isMin) {
  221. var me = this,
  222. d, val;
  223. if (Ext.isString(value)) {
  224. d = me.parseDate(value);
  225. }
  226. else if (Ext.isDate(value)) {
  227. d = value;
  228. }
  229. if (d) {
  230. val = Ext.Date.clearTime(new Date(me.initDate));
  231. val.setHours(d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
  232. }
  233. // Invalid min/maxValue config should result in a null so that defaulting takes over
  234. else {
  235. val = null;
  236. }
  237. me[isMin ? 'minValue' : 'maxValue'] = val;
  238. },
  239. rawToValue: function(rawValue) {
  240. return this.parseDate(rawValue) || rawValue || null;
  241. },
  242. valueToRaw: function(value) {
  243. return this.formatDate(this.parseDate(value));
  244. },
  245. <span id='Ext-form-field-Time-method-getErrors'> /**
  246. </span> * Runs all of Time's validations and returns an array of any errors. Note that this first runs Text's validations,
  247. * so the returned array is an amalgamation of all field errors. The additional validation checks are testing that
  248. * the time format is valid, that the chosen time is within the {@link #minValue} and {@link #maxValue} constraints
  249. * set.
  250. * @param {Object} [value] The value to get errors for (defaults to the current field value)
  251. * @return {String[]} All validation errors for this field
  252. */
  253. getErrors: function(value) {
  254. var me = this,
  255. format = Ext.String.format,
  256. errors = me.callParent(arguments),
  257. minValue = me.minValue,
  258. maxValue = me.maxValue,
  259. date;
  260. value = me.formatDate(value || me.processRawValue(me.getRawValue()));
  261. if (value === null || value.length &lt; 1) { // if it's blank and textfield didn't flag it then it's valid
  262. return errors;
  263. }
  264. date = me.parseDate(value);
  265. if (!date) {
  266. errors.push(format(me.invalidText, value, Ext.Date.unescapeFormat(me.format)));
  267. return errors;
  268. }
  269. if (minValue &amp;&amp; date &lt; minValue) {
  270. errors.push(format(me.minText, me.formatDate(minValue)));
  271. }
  272. if (maxValue &amp;&amp; date &gt; maxValue) {
  273. errors.push(format(me.maxText, me.formatDate(maxValue)));
  274. }
  275. return errors;
  276. },
  277. formatDate: function() {
  278. return Ext.form.field.Date.prototype.formatDate.apply(this, arguments);
  279. },
  280. <span id='Ext-form-field-Time-method-parseDate'> /**
  281. </span> * @private
  282. * Parses an input value into a valid Date object.
  283. * @param {String/Date} value
  284. */
  285. parseDate: function(value) {
  286. var me = this,
  287. val = value,
  288. altFormats = me.altFormats,
  289. altFormatsArray = me.altFormatsArray,
  290. i = 0,
  291. len;
  292. if (value &amp;&amp; !Ext.isDate(value)) {
  293. val = me.safeParse(value, me.format);
  294. if (!val &amp;&amp; altFormats) {
  295. altFormatsArray = altFormatsArray || altFormats.split('|');
  296. len = altFormatsArray.length;
  297. for (; i &lt; len &amp;&amp; !val; ++i) {
  298. val = me.safeParse(value, altFormatsArray[i]);
  299. }
  300. }
  301. }
  302. // If configured to snap, snap resulting parsed Date to the closest increment.
  303. if (val &amp;&amp; me.snapToIncrement) {
  304. val = new Date(Ext.Number.snap(val.getTime(), me.increment * 60 * 1000));
  305. }
  306. return val;
  307. },
  308. safeParse: function(value, format){
  309. var me = this,
  310. utilDate = Ext.Date,
  311. parsedDate,
  312. result = null;
  313. if (utilDate.formatContainsDateInfo(format)) {
  314. // assume we've been given a full date
  315. result = utilDate.parse(value, format);
  316. } else {
  317. // Use our initial safe date
  318. parsedDate = utilDate.parse(me.initDate + ' ' + value, me.initDateFormat + ' ' + format);
  319. if (parsedDate) {
  320. result = parsedDate;
  321. }
  322. }
  323. return result;
  324. },
  325. // @private
  326. getSubmitValue: function() {
  327. var me = this,
  328. format = me.submitFormat || me.format,
  329. value = me.getValue();
  330. return value ? Ext.Date.format(value, format) : null;
  331. },
  332. <span id='Ext-form-field-Time-method-createPicker'> /**
  333. </span> * @private
  334. * Creates the {@link Ext.picker.Time}
  335. */
  336. createPicker: function() {
  337. var me = this,
  338. picker;
  339. me.listConfig = Ext.apply({
  340. xtype: 'timepicker',
  341. selModel: {
  342. mode: 'SINGLE'
  343. },
  344. cls: undefined,
  345. minValue: me.minValue,
  346. maxValue: me.maxValue,
  347. increment: me.increment,
  348. format: me.format,
  349. maxHeight: me.pickerMaxHeight
  350. }, me.listConfig);
  351. picker = me.callParent();
  352. me.store = picker.store;
  353. return picker;
  354. },
  355. onItemClick: function(picker, record){
  356. // The selection change events won't fire when clicking on the selected element. Detect it here.
  357. var me = this,
  358. selected = picker.getSelectionModel().getSelection();
  359. if (selected.length &gt; 0) {
  360. selected = selected[0];
  361. if (selected &amp;&amp; Ext.Date.isEqual(record.get('date'), selected.get('date'))) {
  362. me.collapse();
  363. }
  364. }
  365. },
  366. <span id='Ext-form-field-Time-method-onListSelectionChange'> /**
  367. </span> * @private
  368. * Handles a time being selected from the Time picker.
  369. */
  370. onListSelectionChange: function(list, recordArray) {
  371. var me = this,
  372. record = recordArray[0],
  373. val = record ? record.get('date') : null;
  374. if (!me.ignoreSelection) {
  375. me.skipSync = true;
  376. me.setValue(val);
  377. me.skipSync = false;
  378. me.fireEvent('select', me, val);
  379. me.picker.clearHighlight();
  380. me.collapse();
  381. me.inputEl.focus();
  382. }
  383. },
  384. <span id='Ext-form-field-Time-method-syncSelection'> /**
  385. </span> * @private
  386. * Synchronizes the selection in the picker to match the current value
  387. */
  388. syncSelection: function() {
  389. var me = this,
  390. picker = me.picker,
  391. toSelect,
  392. selModel,
  393. value,
  394. data, d, dLen, rec;
  395. if (picker &amp;&amp; !me.skipSync) {
  396. picker.clearHighlight();
  397. value = me.getValue();
  398. selModel = picker.getSelectionModel();
  399. // Update the selection to match
  400. me.ignoreSelection++;
  401. if (value === null) {
  402. selModel.deselectAll();
  403. } else if(Ext.isDate(value)) {
  404. // find value, select it
  405. data = picker.store.data.items;
  406. dLen = data.length;
  407. for (d = 0; d &lt; dLen; d++) {
  408. rec = data[d];
  409. if (Ext.Date.isEqual(rec.get('date'), value)) {
  410. toSelect = rec;
  411. break;
  412. }
  413. }
  414. selModel.select(toSelect);
  415. }
  416. me.ignoreSelection--;
  417. }
  418. },
  419. postBlur: function() {
  420. var me = this;
  421. me.callParent(arguments);
  422. me.setRawValue(me.formatDate(me.getValue()));
  423. },
  424. setValue: function() {
  425. // Store MUST be created for parent setValue to function
  426. this.getPicker();
  427. this.callParent(arguments);
  428. },
  429. getValue: function() {
  430. return this.parseDate(this.callParent(arguments));
  431. }
  432. });</pre>
  433. </body>
  434. </html>