]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * A modal, floating Component which may be shown above a specified {@link Ext.Component Component} while loading data.\r | |
3 | * When shown, the configured owning Component will be covered with a modality mask, and the LoadMask's {@link #msg} will be\r | |
4 | * displayed centered, accompanied by a spinner image.\r | |
5 | *\r | |
6 | * If the {@link #store} config option is specified, the masking will be automatically shown and then hidden synchronized with\r | |
7 | * the Store's loading process.\r | |
8 | *\r | |
9 | * Because this is a floating Component, its z-index will be managed by the global {@link Ext.WindowManager ZIndexManager}\r | |
10 | * object, and upon show, it will place itsef at the top of the hierarchy.\r | |
11 | *\r | |
12 | * Example usage:\r | |
13 | *\r | |
14 | * @example\r | |
15 | * var myPanel = new Ext.panel.Panel({\r | |
16 | * renderTo : document.body,\r | |
17 | * height : 100,\r | |
18 | * width : 200,\r | |
19 | * title : 'Foo'\r | |
20 | * });\r | |
21 | *\r | |
22 | * var myMask = new Ext.LoadMask({\r | |
23 | * msg : 'Please wait...',\r | |
24 | * target : myPanel\r | |
25 | * });\r | |
26 | *\r | |
27 | * myMask.show();\r | |
28 | */\r | |
29 | Ext.define('Ext.LoadMask', {\r | |
30 | \r | |
31 | extend: 'Ext.Component',\r | |
32 | \r | |
33 | alias: 'widget.loadmask',\r | |
34 | \r | |
35 | /* Begin Definitions */\r | |
36 | \r | |
37 | mixins: [\r | |
38 | 'Ext.util.StoreHolder'\r | |
39 | ],\r | |
40 | \r | |
41 | uses: ['Ext.data.StoreManager'],\r | |
42 | \r | |
43 | /* End Definitions */\r | |
44 | \r | |
45 | /**\r | |
46 | * @property {Boolean} isLoadMask\r | |
47 | * `true` in this class to identify an object as an instantiated LoadMask, or subclass thereof.\r | |
48 | */\r | |
49 | isLoadMask: true,\r | |
50 | \r | |
51 | /**\r | |
52 | * @cfg {Ext.Component} target The Component you wish to mask. The the mask will be automatically sized\r | |
53 | * upon Component resize, and the message box will be kept centered.\r | |
54 | */\r | |
55 | \r | |
56 | /**\r | |
57 | * @cfg {Ext.data.Store} store\r | |
58 | * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and\r | |
59 | * hidden on either load success, or load fail.\r | |
60 | */\r | |
61 | \r | |
62 | //<locale>\r | |
63 | /**\r | |
64 | * @cfg {String} [msg="Loading..."]\r | |
65 | * The text to display in a centered loading message box.\r | |
66 | */\r | |
67 | msg: 'Loading...',\r | |
68 | //</locale>\r | |
69 | \r | |
70 | msgCls: Ext.baseCSSPrefix + 'mask-loading',\r | |
71 | \r | |
72 | msgWrapCls: Ext.baseCSSPrefix + 'mask-msg',\r | |
73 | \r | |
74 | /**\r | |
75 | * @cfg {Boolean} [useMsg=true]\r | |
76 | * Whether or not to use a loading message class or simply mask the bound element.\r | |
77 | */\r | |
78 | useMsg: true,\r | |
79 | \r | |
80 | /**\r | |
81 | * @cfg {Boolean} [useTargetEl=false]\r | |
82 | * True to mask the {@link Ext.Component#getTargetEl targetEl} of the bound Component. By default,\r | |
83 | * the {@link Ext.Component#getEl el} will be masked.\r | |
84 | */\r | |
85 | useTargetEl: false,\r | |
86 | \r | |
87 | /**\r | |
88 | * @cfg {Boolean} shim `true` to enable an iframe shim for this LoadMask to keep\r | |
89 | * windowed objects from showing through.\r | |
90 | */\r | |
91 | \r | |
92 | /**\r | |
93 | * @private\r | |
94 | */\r | |
95 | cls: Ext.baseCSSPrefix + 'mask',\r | |
96 | componentCls: Ext.baseCSSPrefix + 'border-box',\r | |
97 | \r | |
98 | ariaRole: 'status',\r | |
99 | focusable: true,\r | |
100 | tabIndex: 0,\r | |
101 | \r | |
102 | autoEl: {\r | |
103 | tag: 'div',\r | |
104 | role: 'status'\r | |
105 | },\r | |
106 | \r | |
107 | childEls: [\r | |
108 | 'msgWrapEl',\r | |
109 | 'msgEl',\r | |
110 | 'msgTextEl'\r | |
111 | ],\r | |
112 | \r | |
113 | renderTpl: [\r | |
114 | '<div id="{id}-msgWrapEl" data-ref="msgWrapEl" class="{[values.$comp.msgWrapCls]}">',\r | |
115 | '<div id="{id}-msgEl" data-ref="msgEl" class="{[values.$comp.msgCls]} ',\r | |
116 | Ext.baseCSSPrefix, 'mask-msg-inner {childElCls}">',\r | |
117 | '<div id="{id}-msgTextEl" data-ref="msgTextEl" class="',\r | |
118 | Ext.baseCSSPrefix, 'mask-msg-text',\r | |
119 | '{childElCls}">{msg}</div>',\r | |
120 | '</div>',\r | |
121 | '</div>'\r | |
122 | ],\r | |
123 | \r | |
124 | maskOnDisable : false,\r | |
125 | \r | |
126 | /**\r | |
127 | * @private\r | |
128 | */\r | |
129 | skipLayout: true,\r | |
130 | \r | |
131 | /**\r | |
132 | * Creates new LoadMask.\r | |
133 | * @param {Object} [config] The config object.\r | |
134 | */\r | |
135 | constructor : function(config) {\r | |
136 | var me = this,\r | |
137 | comp;\r | |
138 | \r | |
139 | if (arguments.length === 2) {\r | |
140 | //<debug>\r | |
141 | if (Ext.isDefined(Ext.global.console)) {\r | |
142 | Ext.global.console.warn('Ext.LoadMask: LoadMask now uses a standard 1 arg constructor: use the target config');\r | |
143 | }\r | |
144 | //</debug>\r | |
145 | comp = me.target = config;\r | |
146 | config = arguments[1];\r | |
147 | } else {\r | |
148 | comp = config.target;\r | |
149 | }\r | |
150 | \r | |
151 | //<debug>\r | |
152 | if (config.maskCls) {\r | |
153 | Ext.log.warn('Ext.LoadMask property maskCls is deprecated, use msgWrapCls instead');\r | |
154 | config.msgWrapCls = config.msgWrapCls || config.maskCls;\r | |
155 | }\r | |
156 | //</debug>\r | |
157 | \r | |
158 | // Must apply configs early so that renderTo can be calculated correctly.\r | |
159 | me.callParent([config]);\r | |
160 | \r | |
161 | // Target is a Component\r | |
162 | if (comp.isComponent) {\r | |
163 | me.ownerCt = comp;\r | |
164 | me.hidden = true;\r | |
165 | \r | |
166 | // Ask the component which element should be masked.\r | |
167 | // Most will not have an answer, in which case this returns the document body\r | |
168 | // Ext.view.Table for example returns the el of its owning Panel.\r | |
169 | me.renderTo = me.getMaskTarget();\r | |
170 | me.external = me.renderTo === Ext.getBody();\r | |
171 | me.bindComponent(comp);\r | |
172 | }\r | |
173 | // Element support to be deprecated\r | |
174 | else {\r | |
175 | //<debug>\r | |
176 | if (Ext.isDefined(Ext.global.console)) {\r | |
177 | Ext.global.console.warn('Ext.LoadMask: LoadMask for elements has been deprecated, use Ext.dom.Element.mask & Ext.dom.Element.unmask');\r | |
178 | }\r | |
179 | //</debug>\r | |
180 | comp = Ext.get(comp);\r | |
181 | me.isElement = true;\r | |
182 | me.renderTo = me.target;\r | |
183 | }\r | |
184 | me.render(me.renderTo);\r | |
185 | if (me.store) {\r | |
186 | me.bindStore(me.store, true);\r | |
187 | }\r | |
188 | },\r | |
189 | \r | |
190 | initRenderData: function() {\r | |
191 | var result = this.callParent(arguments);\r | |
192 | result.msg = this.msg || '';\r | |
193 | return result;\r | |
194 | },\r | |
195 | \r | |
196 | onRender: function() {\r | |
197 | this.callParent(arguments);\r | |
198 | \r | |
199 | // In versions prior to 5.1, maskEl was rendered outside of the\r | |
200 | // LoadMask's main el and had a reference to it; we keep this\r | |
201 | // reference for backwards compatibility.\r | |
202 | this.maskEl = this.el;\r | |
203 | },\r | |
204 | \r | |
205 | bindComponent: function(comp) {\r | |
206 | var me = this,\r | |
207 | listeners = {\r | |
208 | scope: this,\r | |
209 | resize: me.sizeMask\r | |
210 | };\r | |
211 | \r | |
212 | if (me.external) {\r | |
213 | listeners.added = me.onComponentAdded;\r | |
214 | listeners.removed = me.onComponentRemoved;\r | |
215 | if (comp.floating) {\r | |
216 | listeners.move = me.sizeMask;\r | |
217 | me.activeOwner = comp;\r | |
218 | } else if (comp.ownerCt) {\r | |
219 | me.onComponentAdded(comp.ownerCt);\r | |
220 | }\r | |
221 | }\r | |
222 | \r | |
223 | me.mon(comp, listeners);\r | |
224 | \r | |
225 | // Subscribe to the observer that manages the hierarchy\r | |
226 | // Only needed if we had to be rendered outside of the target\r | |
227 | if (me.external) {\r | |
228 | me.mon(Ext.GlobalEvents, {\r | |
229 | show: me.onContainerShow,\r | |
230 | hide: me.onContainerHide,\r | |
231 | expand: me.onContainerExpand,\r | |
232 | collapse: me.onContainerCollapse,\r | |
233 | scope: me\r | |
234 | });\r | |
235 | }\r | |
236 | },\r | |
237 | \r | |
238 | onComponentAdded: function(owner) {\r | |
239 | var me = this;\r | |
240 | delete me.activeOwner;\r | |
241 | me.floatParent = owner;\r | |
242 | if (!owner.floating) {\r | |
243 | owner = owner.up('[floating]');\r | |
244 | }\r | |
245 | if (owner) {\r | |
246 | me.activeOwner = owner;\r | |
247 | me.mon(owner, 'move', me.sizeMask, me);\r | |
248 | me.mon(owner, 'tofront', me.onOwnerToFront, me);\r | |
249 | } else {\r | |
250 | me.preventBringToFront = true;\r | |
251 | }\r | |
252 | owner = me.floatParent.ownerCt;\r | |
253 | if (me.rendered && me.isVisible() && owner) {\r | |
254 | me.floatOwner = owner;\r | |
255 | me.mon(owner, 'afterlayout', me.sizeMask, me, {single: true});\r | |
256 | }\r | |
257 | },\r | |
258 | \r | |
259 | onComponentRemoved: function(owner) {\r | |
260 | var me = this,\r | |
261 | activeOwner = me.activeOwner,\r | |
262 | floatOwner = me.floatOwner;\r | |
263 | \r | |
264 | if (activeOwner) {\r | |
265 | me.mun(activeOwner, 'move', me.sizeMask, me);\r | |
266 | me.mun(activeOwner, 'tofront', me.onOwnerToFront, me);\r | |
267 | }\r | |
268 | if (floatOwner) {\r | |
269 | me.mun(floatOwner, 'afterlayout', me.sizeMask, me);\r | |
270 | }\r | |
271 | delete me.activeOwner;\r | |
272 | delete me.floatOwner;\r | |
273 | },\r | |
274 | \r | |
275 | afterRender: function() {\r | |
276 | var me = this;\r | |
277 | \r | |
278 | me.callParent(arguments);\r | |
279 | \r | |
280 | // In IE8-11, clicking on an inner msgEl will focus it, despite\r | |
281 | // it having no tabindex attribute and thus being canonically\r | |
282 | // non-focusable. Placing unselectable="on" attribute will make\r | |
283 | // it unfocusable but will also prevent clicks from focusing\r | |
284 | // the parent element. We want clicks within the mask's main el\r | |
285 | // to focus it, hence the workaround.\r | |
286 | if (Ext.isIE) {\r | |
287 | me.el.on('mousedown', me.onMouseDown, me);\r | |
288 | }\r | |
289 | \r | |
290 | // This LoadMask shares the DOM and may be tipped out by the use of innerHTML\r | |
291 | // Ensure the element does not get garbage collected from under us.\r | |
292 | this.el.skipGarbageCollection = true;\r | |
293 | },\r | |
294 | \r | |
295 | onMouseDown: function(e) {\r | |
296 | var el = this.el;\r | |
297 | \r | |
298 | if (e.within(el)) {\r | |
299 | e.preventDefault();\r | |
300 | el.focus();\r | |
301 | }\r | |
302 | },\r | |
303 | \r | |
304 | onOwnerToFront: function(owner, zIndex) {\r | |
305 | this.el.setStyle('zIndex', zIndex + 1);\r | |
306 | },\r | |
307 | \r | |
308 | // Only called if we are rendered external to the target.\r | |
309 | // Best we can do is show.\r | |
310 | onContainerShow: function(container) {\r | |
311 | if (!this.isHierarchicallyHidden()) {\r | |
312 | this.onComponentShow();\r | |
313 | }\r | |
314 | },\r | |
315 | \r | |
316 | // Only called if we are rendered external to the target.\r | |
317 | // Best we can do is hide.\r | |
318 | onContainerHide: function(container) {\r | |
319 | if (this.isHierarchicallyHidden()) {\r | |
320 | this.onComponentHide();\r | |
321 | }\r | |
322 | },\r | |
323 | \r | |
324 | // Only called if we are rendered external to the target.\r | |
325 | // Best we can do is show.\r | |
326 | onContainerExpand: function(container) {\r | |
327 | if (!this.isHierarchicallyHidden()) {\r | |
328 | this.onComponentShow();\r | |
329 | }\r | |
330 | },\r | |
331 | \r | |
332 | // Only called if we are rendered external to the target.\r | |
333 | // Best we can do is hide.\r | |
334 | onContainerCollapse: function(container) {\r | |
335 | if (this.isHierarchicallyHidden()) {\r | |
336 | this.onComponentHide();\r | |
337 | }\r | |
338 | },\r | |
339 | \r | |
340 | onComponentHide: function() {\r | |
341 | var me = this;\r | |
342 | \r | |
343 | if (me.rendered && me.isVisible()) {\r | |
344 | me.hide();\r | |
345 | me.showNext = true;\r | |
346 | }\r | |
347 | },\r | |
348 | \r | |
349 | onComponentShow: function() {\r | |
350 | if (this.showNext) {\r | |
351 | this.show();\r | |
352 | }\r | |
353 | delete this.showNext;\r | |
354 | },\r | |
355 | \r | |
356 | /**\r | |
357 | * @private\r | |
358 | * Called when this LoadMask's Component is resized. The toFront method rebases and resizes the modal mask.\r | |
359 | */\r | |
360 | sizeMask: function() {\r | |
361 | var me = this,\r | |
362 | // Need to use the closest floating component (if it exists) as the basis\r | |
363 | // for our z-index positioning\r | |
364 | target = me.activeOwner || me.target,\r | |
365 | boxTarget = me.external ? me.getOwner().el : me.getMaskTarget();\r | |
366 | \r | |
367 | if (me.rendered && me.isVisible()) {\r | |
368 | // Only need to move and size the message wrap if we are outside of\r | |
369 | // the masked element.\r | |
370 | // If we are inside, it will be left:0;top:0;width:100%;height:100% by default\r | |
371 | if (me.external) {\r | |
372 | if (!me.isElement && target.floating) {\r | |
373 | me.onOwnerToFront(target, target.el.getZIndex());\r | |
374 | }\r | |
375 | me.el.setSize(boxTarget.getSize()).alignTo(boxTarget, 'tl-tl');\r | |
376 | }\r | |
377 | \r | |
378 | // Always need to center the message wrap\r | |
379 | me.msgWrapEl.center(me.el);\r | |
380 | }\r | |
381 | },\r | |
382 | \r | |
383 | /**\r | |
384 | * Changes the data store bound to this LoadMask.\r | |
385 | * @param {Ext.data.Store} store The store to bind to this LoadMask\r | |
386 | */\r | |
387 | bindStore : function(store, initial) {\r | |
388 | var me = this;\r | |
389 | \r | |
390 | // If the server returns a failure, and the proxy fires an exception instead of\r | |
391 | // loading the store, the mask must clear.\r | |
392 | Ext.destroy(me.proxyListeners);\r | |
393 | \r | |
394 | me.mixins.storeholder.bindStore.apply(me, arguments);\r | |
395 | store = me.store;\r | |
396 | \r | |
397 | if (store) {\r | |
398 | // Skip ChainedStores to the store that does the loading\r | |
399 | while (store.getSource) {\r | |
400 | store = store.getSource();\r | |
401 | }\r | |
402 | if (!store.loadsSynchronously()) {\r | |
403 | me.proxyListeners = store.getProxy().on({\r | |
404 | exception: me.onLoad,\r | |
405 | scope: me,\r | |
406 | destroyable: true\r | |
407 | });\r | |
408 | }\r | |
409 | \r | |
410 | if (store.isLoading()) {\r | |
411 | me.onBeforeLoad();\r | |
412 | }\r | |
413 | }\r | |
414 | },\r | |
415 | \r | |
416 | getStoreListeners: function(store) {\r | |
417 | var onLoad = this.onLoad,\r | |
418 | beforeLoad = this.onBeforeLoad,\r | |
419 | result = {\r | |
420 | // Fired when a range is requested for rendering that is not in the cache\r | |
421 | cachemiss: beforeLoad,\r | |
422 | \r | |
423 | // Fired when a range for rendering which was previously missing from the cache is loaded.\r | |
424 | // buffer so that scrolling and store filling has settled, and the results have been rendered.\r | |
425 | cachefilled: {\r | |
426 | fn: onLoad,\r | |
427 | buffer: 100\r | |
428 | }\r | |
429 | };\r | |
430 | \r | |
431 | // Only need to mask on load if the proxy is asynchronous - ie: Ajax/JsonP\r | |
432 | if (!store.loadsSynchronously()) {\r | |
433 | result.beforeload = beforeLoad;\r | |
434 | result.load = onLoad;\r | |
435 | }\r | |
436 | return result;\r | |
437 | },\r | |
438 | \r | |
439 | onDisable : function() {\r | |
440 | this.callParent(arguments);\r | |
441 | if (this.loading) {\r | |
442 | this.onLoad();\r | |
443 | }\r | |
444 | },\r | |
445 | \r | |
446 | getOwner: function() {\r | |
447 | return this.ownerCt || this.ownerCmp || this.floatParent;\r | |
448 | },\r | |
449 | \r | |
450 | getMaskTarget: function() {\r | |
451 | var owner = this.getOwner();\r | |
452 | if (this.isElement) {\r | |
453 | return this.target;\r | |
454 | }\r | |
455 | return this.useTargetEl ? owner.getTargetEl() : (owner.getMaskTarget() || Ext.getBody());\r | |
456 | },\r | |
457 | \r | |
458 | /**\r | |
459 | * @private\r | |
460 | */\r | |
461 | onBeforeLoad : function() {\r | |
462 | var me = this,\r | |
463 | owner = me.getOwner(),\r | |
464 | origin;\r | |
465 | \r | |
466 | if (!me.disabled) {\r | |
467 | me.loading = true;\r | |
468 | // If the owning Component has not been layed out, defer so that the ZIndexManager\r | |
469 | // gets to read its layed out size when sizing the modal mask\r | |
470 | if (owner.componentLayoutCounter) {\r | |
471 | me.maybeShow();\r | |
472 | } else {\r | |
473 | // The code below is a 'run-once' interceptor.\r | |
474 | origin = owner.afterComponentLayout;\r | |
475 | owner.afterComponentLayout = function() {\r | |
476 | owner.afterComponentLayout = origin;\r | |
477 | origin.apply(owner, arguments);\r | |
478 | me.maybeShow();\r | |
479 | };\r | |
480 | }\r | |
481 | }\r | |
482 | },\r | |
483 | \r | |
484 | maybeShow: function() {\r | |
485 | var me = this,\r | |
486 | owner = me.getOwner();\r | |
487 | \r | |
488 | if (!owner.isVisible(true)) {\r | |
489 | me.showNext = true;\r | |
490 | }\r | |
491 | else if (me.loading && owner.rendered) {\r | |
492 | me.show();\r | |
493 | }\r | |
494 | },\r | |
495 | \r | |
496 | hide: function() {\r | |
497 | var me = this,\r | |
498 | ownerCt = me.ownerCt;\r | |
499 | \r | |
500 | // Element support to be deprecated\r | |
501 | if (me.isElement) {\r | |
502 | ownerCt.unmask();\r | |
503 | me.fireEvent('hide', this);\r | |
504 | \r | |
505 | return;\r | |
506 | }\r | |
507 | \r | |
508 | // Could be already nulled while destroying\r | |
509 | if (ownerCt) {\r | |
510 | ownerCt.enableTabbing();\r | |
511 | ownerCt.setMasked(false);\r | |
512 | }\r | |
513 | \r | |
514 | delete me.showNext;\r | |
515 | \r | |
516 | return me.callParent(arguments);\r | |
517 | },\r | |
518 | \r | |
519 | show: function() {\r | |
520 | var me = this;\r | |
521 | \r | |
522 | // Element support to be deprecated\r | |
523 | if (me.isElement) {\r | |
524 | me.ownerCt.mask(this.useMsg ? this.msg : '', this.msgCls);\r | |
525 | me.fireEvent('show', this);\r | |
526 | \r | |
527 | return;\r | |
528 | }\r | |
529 | \r | |
530 | return me.callParent(arguments);\r | |
531 | },\r | |
532 | \r | |
533 | afterShow: function() { \r | |
534 | var me = this,\r | |
535 | ownerCt = me.ownerCt;\r | |
536 | \r | |
537 | me.loading = true;\r | |
538 | me.callParent(arguments);\r | |
539 | \r | |
540 | ownerCt.disableTabbing();\r | |
541 | ownerCt.setMasked(true);\r | |
542 | \r | |
543 | // Owner's disabled tabbing will also make the mask\r | |
544 | // untabbable since it is rendered within the target\r | |
545 | me.el.restoreTabbableState();\r | |
546 | \r | |
547 | me.syncMaskState();\r | |
548 | },\r | |
549 | \r | |
550 | /**\r | |
551 | * Synchronizes the visible state of the mask with the configuration settings such\r | |
552 | * as {@link #msgWrapCls}, {@link #msg}, sizes the mask to occlude the target element or Component\r | |
553 | * and focuses the mask.\r | |
554 | * @private\r | |
555 | */\r | |
556 | syncMaskState: function() {\r | |
557 | var me = this,\r | |
558 | ownerCt = me.ownerCt,\r | |
559 | el = me.el;\r | |
560 | \r | |
561 | if (me.isVisible()) {\r | |
562 | \r | |
563 | // Allow dynamic setting of msgWrapCls\r | |
564 | if (me.hasOwnProperty('msgWrapCls')) {\r | |
565 | el.dom.className = me.msgWrapCls;\r | |
566 | }\r | |
567 | \r | |
568 | if (me.useMsg) {\r | |
569 | me.msgTextEl.setHtml(me.msg);\r | |
570 | } else {\r | |
571 | // Only the mask is visible if useMsg is false\r | |
572 | me.msgEl.hide();\r | |
573 | }\r | |
574 | \r | |
575 | if (me.shim || Ext.useShims) {\r | |
576 | el.enableShim(null, true);\r | |
577 | } else {\r | |
578 | // Just in case me.shim was changed since last time we were shown (by\r | |
579 | // Component#setLoading())\r | |
580 | el.disableShim();\r | |
581 | }\r | |
582 | \r | |
583 | // If owner contains focus, focus this.\r | |
584 | // Component level onHide processing takes care of focus reversion on hide.\r | |
585 | if (ownerCt.el.contains(Ext.Element.getActiveElement())) {\r | |
586 | me.focus();\r | |
587 | }\r | |
588 | me.sizeMask();\r | |
589 | }\r | |
590 | },\r | |
591 | \r | |
592 | /**\r | |
593 | * @private\r | |
594 | */\r | |
595 | onLoad : function() {\r | |
596 | this.loading = false;\r | |
597 | this.hide();\r | |
598 | },\r | |
599 | \r | |
600 | beforeDestroy: function() {\r | |
601 | // We don't have a real ownerCt, so clear it out here to prevent\r | |
602 | // spurious warnings when we are destroyed\r | |
603 | this.ownerCt = null;\r | |
604 | this.bindStore(null);\r | |
605 | this.callParent();\r | |
606 | },\r | |
607 | \r | |
608 | onDestroy: function() {\r | |
609 | var me = this;\r | |
610 | \r | |
611 | if (me.isElement) {\r | |
612 | me.ownerCt.unmask();\r | |
613 | }\r | |
614 | \r | |
615 | me.callParent();\r | |
616 | }\r | |
617 | });\r |