Trigger2.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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-Trigger'>/**
  19. </span> * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
  20. * The trigger has no default action, so you must assign a function to implement the trigger click handler by overriding
  21. * {@link #onTriggerClick}. You can create a Trigger field directly, as it renders exactly like a combobox for which you
  22. * can provide a custom implementation.
  23. *
  24. * For example:
  25. *
  26. * @example
  27. * Ext.define('Ext.ux.CustomTrigger', {
  28. * extend: 'Ext.form.field.Trigger',
  29. * alias: 'widget.customtrigger',
  30. *
  31. * // override onTriggerClick
  32. * onTriggerClick: function() {
  33. * Ext.Msg.alert('Status', 'You clicked my trigger!');
  34. * }
  35. * });
  36. *
  37. * Ext.create('Ext.form.FormPanel', {
  38. * title: 'Form with TriggerField',
  39. * bodyPadding: 5,
  40. * width: 350,
  41. * renderTo: Ext.getBody(),
  42. * items:[{
  43. * xtype: 'customtrigger',
  44. * fieldLabel: 'Sample Trigger',
  45. * emptyText: 'click the trigger'
  46. * }]
  47. * });
  48. *
  49. * However, in general you will most likely want to use Trigger as the base class for a reusable component.
  50. * {@link Ext.form.field.Date} and {@link Ext.form.field.ComboBox} are perfect examples of this.
  51. */
  52. Ext.define('Ext.form.field.Trigger', {
  53. extend:'Ext.form.field.Text',
  54. alias: ['widget.triggerfield', 'widget.trigger'],
  55. requires: ['Ext.DomHelper', 'Ext.util.ClickRepeater', 'Ext.layout.component.field.Trigger'],
  56. alternateClassName: ['Ext.form.TriggerField', 'Ext.form.TwinTriggerField', 'Ext.form.Trigger'],
  57. childEls: [
  58. <span id='Ext-form-field-Trigger-property-triggerEl'> /**
  59. </span> * @property {Ext.CompositeElement} triggerEl
  60. * A composite of all the trigger button elements. Only set after the field has been rendered.
  61. */
  62. { name: 'triggerCell', select: '.' + Ext.baseCSSPrefix + 'trigger-cell' },
  63. { name: 'triggerEl', select: '.' + Ext.baseCSSPrefix + 'form-trigger' },
  64. <span id='Ext-form-field-Trigger-property-triggerWrap'> /**
  65. </span> * @property {Ext.Element} triggerWrap
  66. * A reference to the `TABLE` element which encapsulates the input field and all trigger button(s). Only set after the field has been rendered.
  67. */
  68. 'triggerWrap',
  69. <span id='Ext-form-field-Trigger-property-inputCell'> /**
  70. </span> * @property {Ext.Element} inputCell
  71. * A reference to the `TD` element wrapping the input element. Only set after the field has been rendered.
  72. */
  73. 'inputCell'
  74. ],
  75. <span id='Ext-form-field-Trigger-cfg-triggerCls'> /**
  76. </span> * @cfg {String} triggerCls
  77. * An additional CSS class used to style the trigger button. The trigger will always get the {@link #triggerBaseCls}
  78. * by default and triggerCls will be **appended** if specified.
  79. */
  80. <span id='Ext-form-field-Trigger-cfg-triggerBaseCls'> /**
  81. </span> * @cfg
  82. * The base CSS class that is always added to the trigger button. The {@link #triggerCls} will be appended in
  83. * addition to this class.
  84. */
  85. triggerBaseCls: Ext.baseCSSPrefix + 'form-trigger',
  86. <span id='Ext-form-field-Trigger-cfg-triggerWrapCls'> /**
  87. </span> * @cfg
  88. * The CSS class that is added to the div wrapping the trigger button(s).
  89. */
  90. triggerWrapCls: Ext.baseCSSPrefix + 'form-trigger-wrap',
  91. <span id='Ext-form-field-Trigger-cfg-triggerNoEditCls'> /**
  92. </span> * @cfg
  93. * The CSS class that is added to the text field when component is read-only or not editable.
  94. */
  95. triggerNoEditCls: Ext.baseCSSPrefix + 'trigger-noedit',
  96. <span id='Ext-form-field-Trigger-cfg-hideTrigger'> /**
  97. </span> * @cfg {Boolean} hideTrigger
  98. * true to hide the trigger element and display only the base text field
  99. */
  100. hideTrigger: false,
  101. <span id='Ext-form-field-Trigger-cfg-editable'> /**
  102. </span> * @cfg {Boolean} editable
  103. * false to prevent the user from typing text directly into the field; the field can only have its value set via an
  104. * action invoked by the trigger.
  105. */
  106. editable: true,
  107. <span id='Ext-form-field-Trigger-cfg-readOnly'> /**
  108. </span> * @cfg {Boolean} readOnly
  109. * true to prevent the user from changing the field, and hides the trigger. Supercedes the editable and hideTrigger
  110. * options if the value is true.
  111. */
  112. readOnly: false,
  113. <span id='Ext-form-field-Trigger-cfg-selectOnFocus'> /**
  114. </span> * @cfg {Boolean} [selectOnFocus=false]
  115. * true to select any existing text in the field immediately on focus. Only applies when
  116. * {@link #editable editable} = true
  117. */
  118. <span id='Ext-form-field-Trigger-cfg-repeatTriggerClick'> /**
  119. </span> * @cfg {Boolean} repeatTriggerClick
  120. * true to attach a {@link Ext.util.ClickRepeater click repeater} to the trigger.
  121. */
  122. repeatTriggerClick: false,
  123. <span id='Ext-form-field-Trigger-method-autoSize'> /**
  124. </span> * @method autoSize
  125. * @private
  126. */
  127. autoSize: Ext.emptyFn,
  128. // private
  129. monitorTab: true,
  130. // private
  131. mimicing: false,
  132. // private
  133. triggerIndexRe: /trigger-index-(\d+)/,
  134. componentLayout: 'triggerfield',
  135. initComponent: function() {
  136. this.wrapFocusCls = this.triggerWrapCls + '-focus';
  137. this.callParent(arguments);
  138. },
  139. getSubTplMarkup: function() {
  140. var me = this,
  141. field = me.callParent(arguments);
  142. return '&lt;table id=&quot;' + me.id + '-triggerWrap&quot; class=&quot;' + Ext.baseCSSPrefix + 'form-trigger-wrap&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tbody&gt;&lt;tr&gt;' +
  143. '&lt;td id=&quot;' + me.id + '-inputCell&quot; class=&quot;' + Ext.baseCSSPrefix + 'form-trigger-input-cell&quot;&gt;' + field + '&lt;/td&gt;' +
  144. me.getTriggerMarkup() +
  145. '&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;';
  146. },
  147. getSubTplData: function(){
  148. var me = this,
  149. data = me.callParent(),
  150. readOnly = me.readOnly === true,
  151. editable = me.editable !== false;
  152. return Ext.apply(data, {
  153. editableCls: (readOnly || !editable) ? ' ' + me.triggerNoEditCls : '',
  154. readOnly: !editable || readOnly
  155. });
  156. },
  157. getLabelableRenderData: function() {
  158. var me = this,
  159. triggerWrapCls = me.triggerWrapCls,
  160. result = me.callParent(arguments);
  161. return Ext.applyIf(result, {
  162. triggerWrapCls: triggerWrapCls,
  163. triggerMarkup: me.getTriggerMarkup()
  164. });
  165. },
  166. getTriggerMarkup: function() {
  167. var me = this,
  168. i = 0,
  169. hideTrigger = (me.readOnly || me.hideTrigger),
  170. triggerCls,
  171. triggerBaseCls = me.triggerBaseCls,
  172. triggerConfigs = [];
  173. // TODO this trigger&lt;n&gt;Cls API design doesn't feel clean, especially where it butts up against the
  174. // single triggerCls config. Should rethink this, perhaps something more structured like a list of
  175. // trigger config objects that hold cls, handler, etc.
  176. // triggerCls is a synonym for trigger1Cls, so copy it.
  177. if (!me.trigger1Cls) {
  178. me.trigger1Cls = me.triggerCls;
  179. }
  180. // Create as many trigger elements as we have trigger&lt;n&gt;Cls configs, but always at least one
  181. for (i = 0; (triggerCls = me['trigger' + (i + 1) + 'Cls']) || i &lt; 1; i++) {
  182. triggerConfigs.push({
  183. tag: 'td',
  184. valign: 'top',
  185. cls: Ext.baseCSSPrefix + 'trigger-cell',
  186. style: 'width:' + me.triggerWidth + (hideTrigger ? 'px;display:none' : 'px'),
  187. cn: {
  188. cls: [Ext.baseCSSPrefix + 'trigger-index-' + i, triggerBaseCls, triggerCls].join(' '),
  189. role: 'button'
  190. }
  191. });
  192. }
  193. triggerConfigs[i - 1].cn.cls += ' ' + triggerBaseCls + '-last';
  194. return Ext.DomHelper.markup(triggerConfigs);
  195. },
  196. disableCheck: function() {
  197. return !this.disabled;
  198. },
  199. // private
  200. beforeRender: function() {
  201. var me = this,
  202. triggerBaseCls = me.triggerBaseCls,
  203. tempEl;
  204. <span id='Ext-form-field-Trigger-property-triggerWidth'> /**
  205. </span> * @property {Number} triggerWidth
  206. * Width of the trigger element. Unless set explicitly, it will be
  207. * automatically calculated through creating a temporary element
  208. * on page. (That will be done just once per app run.)
  209. * @private
  210. */
  211. if (!me.triggerWidth) {
  212. tempEl = Ext.resetElement.createChild({
  213. style: 'position: absolute;',
  214. cls: Ext.baseCSSPrefix + 'form-trigger'
  215. });
  216. Ext.form.field.Trigger.prototype.triggerWidth = tempEl.getWidth();
  217. tempEl.remove();
  218. }
  219. me.callParent();
  220. if (triggerBaseCls != Ext.baseCSSPrefix + 'form-trigger') {
  221. // we may need to change the selectors by which we extract trigger elements if is triggerBaseCls isn't the value we
  222. // stuck in childEls
  223. me.addChildEls({ name: 'triggerEl', select: '.' + triggerBaseCls });
  224. }
  225. // these start correct in the fieldSubTpl:
  226. me.lastTriggerStateFlags = me.getTriggerStateFlags();
  227. },
  228. onRender: function() {
  229. var me = this;
  230. me.callParent(arguments);
  231. me.doc = Ext.getDoc();
  232. me.initTrigger();
  233. me.triggerEl.unselectable();
  234. },
  235. <span id='Ext-form-field-Trigger-method-getTriggerWidth'> /**
  236. </span> * Get the total width of the trigger button area.
  237. * @return {Number} The total trigger width
  238. */
  239. getTriggerWidth: function() {
  240. var me = this,
  241. totalTriggerWidth = 0;
  242. if (me.triggerWrap &amp;&amp; !me.hideTrigger &amp;&amp; !me.readOnly) {
  243. totalTriggerWidth = me.triggerEl.getCount() * me.triggerWidth;
  244. }
  245. return totalTriggerWidth;
  246. },
  247. setHideTrigger: function(hideTrigger) {
  248. if (hideTrigger != this.hideTrigger) {
  249. this.hideTrigger = hideTrigger;
  250. this.updateLayout();
  251. }
  252. },
  253. <span id='Ext-form-field-Trigger-method-setEditable'> /**
  254. </span> * Sets the editable state of this field. This method is the runtime equivalent of setting the 'editable' config
  255. * option at config time.
  256. * @param {Boolean} editable True to allow the user to directly edit the field text. If false is passed, the user
  257. * will only be able to modify the field using the trigger. Will also add a click event to the text field which
  258. * will call the trigger.
  259. */
  260. setEditable: function(editable) {
  261. if (editable != this.editable) {
  262. this.editable = editable;
  263. this.updateLayout();
  264. }
  265. },
  266. <span id='Ext-form-field-Trigger-method-setReadOnly'> /**
  267. </span> * Sets the read-only state of this field. This method is the runtime equivalent of setting the 'readOnly' config
  268. * option at config time.
  269. * @param {Boolean} readOnly True to prevent the user changing the field and explicitly hide the trigger. Setting
  270. * this to true will supercede settings editable and hideTrigger. Setting this to false will defer back to editable
  271. * and hideTrigger.
  272. */
  273. setReadOnly: function(readOnly) {
  274. if (readOnly != this.readOnly) {
  275. this.readOnly = readOnly;
  276. this.updateLayout();
  277. }
  278. },
  279. // private
  280. initTrigger: function() {
  281. var me = this,
  282. triggerWrap = me.triggerWrap,
  283. triggerEl = me.triggerEl,
  284. disableCheck = me.disableCheck,
  285. els, eLen, el, e, idx;
  286. if (me.repeatTriggerClick) {
  287. me.triggerRepeater = new Ext.util.ClickRepeater(triggerWrap, {
  288. preventDefault: true,
  289. handler: me.onTriggerWrapClick,
  290. listeners: {
  291. mouseup: me.onTriggerWrapMouseup,
  292. scope: me
  293. },
  294. scope: me
  295. });
  296. } else {
  297. me.mon(triggerWrap, {
  298. click: me.onTriggerWrapClick,
  299. mouseup: me.onTriggerWrapMouseup,
  300. scope: me
  301. });
  302. }
  303. triggerEl.setVisibilityMode(Ext.Element.DISPLAY);
  304. triggerEl.addClsOnOver(me.triggerBaseCls + '-over', disableCheck, me);
  305. els = triggerEl.elements;
  306. eLen = els.length;
  307. for (e = 0; e &lt; eLen; e++) {
  308. el = els[e];
  309. idx = e+1;
  310. el.addClsOnOver(me['trigger' + (idx) + 'Cls'] + '-over', disableCheck, me);
  311. el.addClsOnClick(me['trigger' + (idx) + 'Cls'] + '-click', disableCheck, me);
  312. }
  313. triggerEl.addClsOnClick(me.triggerBaseCls + '-click', disableCheck, me);
  314. },
  315. // private
  316. onDestroy: function() {
  317. var me = this;
  318. Ext.destroyMembers(me, 'triggerRepeater', 'triggerWrap', 'triggerEl');
  319. delete me.doc;
  320. me.callParent();
  321. },
  322. // private
  323. onFocus: function() {
  324. var me = this;
  325. me.callParent(arguments);
  326. if (!me.mimicing) {
  327. me.bodyEl.addCls(me.wrapFocusCls);
  328. me.mimicing = true;
  329. me.mon(me.doc, 'mousedown', me.mimicBlur, me, {
  330. delay: 10
  331. });
  332. if (me.monitorTab) {
  333. me.on('specialkey', me.checkTab, me);
  334. }
  335. }
  336. },
  337. // private
  338. checkTab: function(me, e) {
  339. if (!this.ignoreMonitorTab &amp;&amp; e.getKey() == e.TAB) {
  340. this.triggerBlur();
  341. }
  342. },
  343. <span id='Ext-form-field-Trigger-method-getTriggerStateFlags'> /**
  344. </span> * Returns a set of flags that describe the trigger state. These are just used to easily
  345. * determine if the DOM is out-of-sync with the component's properties.
  346. * @private
  347. */
  348. getTriggerStateFlags: function () {
  349. var me = this,
  350. state = 0;
  351. if (me.readOnly) {
  352. state += 1;
  353. }
  354. if (me.editable) {
  355. state += 2;
  356. }
  357. if (me.hideTrigger) {
  358. state += 4;
  359. }
  360. return state;
  361. },
  362. <span id='Ext-form-field-Trigger-method-onBlur'> /**
  363. </span> * @private
  364. * The default blur handling must not occur for a TriggerField, implementing this template method as emptyFn disables that.
  365. * Instead the tab key is monitored, and the superclass's onBlur is called when tab is detected
  366. */
  367. onBlur: Ext.emptyFn,
  368. // private
  369. mimicBlur: function(e) {
  370. if (!this.isDestroyed &amp;&amp; !this.bodyEl.contains(e.target) &amp;&amp; this.validateBlur(e)) {
  371. this.triggerBlur(e);
  372. }
  373. },
  374. // private
  375. triggerBlur: function(e) {
  376. var me = this;
  377. me.mimicing = false;
  378. me.mun(me.doc, 'mousedown', me.mimicBlur, me);
  379. if (me.monitorTab &amp;&amp; me.inputEl) {
  380. me.un('specialkey', me.checkTab, me);
  381. }
  382. Ext.form.field.Trigger.superclass.onBlur.call(me, e);
  383. if (me.bodyEl) {
  384. me.bodyEl.removeCls(me.wrapFocusCls);
  385. }
  386. },
  387. // private
  388. // This should be overridden by any subclass that needs to check whether or not the field can be blurred.
  389. validateBlur: function(e) {
  390. return true;
  391. },
  392. // private
  393. // process clicks upon triggers.
  394. // determine which trigger index, and dispatch to the appropriate click handler
  395. onTriggerWrapClick: function() {
  396. var me = this,
  397. targetEl, match,
  398. triggerClickMethod,
  399. event;
  400. event = arguments[me.triggerRepeater ? 1 : 0];
  401. if (event &amp;&amp; !me.readOnly &amp;&amp; !me.disabled) {
  402. targetEl = event.getTarget('.' + me.triggerBaseCls, null);
  403. match = targetEl &amp;&amp; targetEl.className.match(me.triggerIndexRe);
  404. if (match) {
  405. triggerClickMethod = me['onTrigger' + (parseInt(match[1], 10) + 1) + 'Click'] || me.onTriggerClick;
  406. if (triggerClickMethod) {
  407. triggerClickMethod.call(me, event);
  408. }
  409. }
  410. }
  411. },
  412. // private
  413. // Handle trigger mouse up gesture. To be implemented in subclasses.
  414. // Currently the Spinner subclass refocuses the input element upon end of spin.
  415. onTriggerWrapMouseup: Ext.emptyFn,
  416. <span id='Ext-form-field-Trigger-method-onTriggerClick'> /**
  417. </span> * @method onTriggerClick
  418. * @protected
  419. * The function that should handle the trigger's click event. This method does nothing by default until overridden
  420. * by an implementing function. See Ext.form.field.ComboBox and Ext.form.field.Date for sample implementations.
  421. * @param {Ext.EventObject} e
  422. */
  423. onTriggerClick: Ext.emptyFn
  424. <span id='Ext-form-field-Trigger-cfg-grow'> /**
  425. </span> * @cfg {Boolean} grow
  426. * @private
  427. */
  428. <span id='Ext-form-field-Trigger-cfg-growMin'> /**
  429. </span> * @cfg {Number} growMin
  430. * @private
  431. */
  432. <span id='Ext-form-field-Trigger-cfg-growMax'> /**
  433. </span> * @cfg {Number} growMax
  434. * @private
  435. */
  436. });
  437. </pre>
  438. </body>
  439. </html>