LoadMask.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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-LoadMask'>/**
  19. </span> * A modal, floating Component which may be shown above a specified {@link Ext.Component Component} while loading data.
  20. * When shown, the configured owning Component will be covered with a modality mask, and the LoadMask's {@link #msg} will be
  21. * displayed centered, accompanied by a spinner image.
  22. *
  23. * If the {@link #store} config option is specified, the masking will be automatically shown and then hidden synchronized with
  24. * the Store's loading process.
  25. *
  26. * Because this is a floating Component, its z-index will be managed by the global {@link Ext.WindowManager ZIndexManager}
  27. * object, and upon show, it will place itsef at the top of the hierarchy.
  28. *
  29. * Example usage:
  30. *
  31. * // Basic mask:
  32. * var myMask = new Ext.LoadMask(myPanel, {msg:&quot;Please wait...&quot;});
  33. * myMask.show();
  34. */
  35. Ext.define('Ext.LoadMask', {
  36. extend: 'Ext.Component',
  37. alias: 'widget.loadmask',
  38. /* Begin Definitions */
  39. mixins: {
  40. floating: 'Ext.util.Floating',
  41. bindable: 'Ext.util.Bindable'
  42. },
  43. uses: ['Ext.data.StoreManager'],
  44. /* End Definitions */
  45. <span id='Ext-LoadMask-cfg-store'> /**
  46. </span> * @cfg {Ext.data.Store} store
  47. * Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
  48. * hidden on either load success, or load fail.
  49. */
  50. //&lt;locale&gt;
  51. <span id='Ext-LoadMask-cfg-msg'> /**
  52. </span> * @cfg {String} [msg=&quot;Loading...&quot;]
  53. * The text to display in a centered loading message box.
  54. */
  55. msg : 'Loading...',
  56. //&lt;/locale&gt;
  57. <span id='Ext-LoadMask-cfg-msgCls'> /**
  58. </span> * @cfg {String} [msgCls=&quot;x-mask-loading&quot;]
  59. * The CSS class to apply to the loading message element.
  60. */
  61. msgCls : Ext.baseCSSPrefix + 'mask-loading',
  62. <span id='Ext-LoadMask-cfg-maskCls'> /**
  63. </span> * @cfg {String} [maskCls=&quot;x-mask&quot;]
  64. * The CSS class to apply to the mask element
  65. */
  66. maskCls: Ext.baseCSSPrefix + 'mask',
  67. <span id='Ext-LoadMask-cfg-useMsg'> /**
  68. </span> * @cfg {Boolean} [useMsg=true]
  69. * Whether or not to use a loading message class or simply mask the bound element.
  70. */
  71. useMsg: true,
  72. <span id='Ext-LoadMask-cfg-useTargetEl'> /**
  73. </span> * @cfg {Boolean} [useTargetEl=false]
  74. * True to mask the {@link Ext.Component#getTargetEl targetEl} of the bound Component. By default,
  75. * the {@link Ext.Component#getEl el} will be masked.
  76. */
  77. useTargetEl: false,
  78. baseCls: Ext.baseCSSPrefix + 'mask-msg',
  79. childEls: [
  80. 'msgEl'
  81. ],
  82. renderTpl: '&lt;div id=&quot;{id}-msgEl&quot; style=&quot;position:relative&quot; class=&quot;{[values.$comp.msgCls]}&quot;&gt;&lt;/div&gt;',
  83. // Private. Obviously, it's floating.
  84. floating: {
  85. shadow: 'frame'
  86. },
  87. // Private. Masks are not focusable
  88. focusOnToFront: false,
  89. // When we put the load mask to the front of it's owner, we generally don't want to also bring the owning
  90. // component to the front.
  91. bringParentToFront: false,
  92. <span id='Ext-LoadMask-method-constructor'> /**
  93. </span> * Creates new LoadMask.
  94. * @param {Ext.Component} comp The Component you wish to mask. The the mask will be automatically sized
  95. * upon Component resize, and the message box will be kept centered.&lt;/p&gt;
  96. * @param {Object} [config] The config object
  97. */
  98. constructor : function(comp, config) {
  99. var me = this;
  100. // Element support to be deprecated
  101. if (!comp.isComponent) {
  102. //&lt;debug&gt;
  103. if (Ext.isDefined(Ext.global.console)) {
  104. Ext.global.console.warn('Ext.LoadMask: LoadMask for elements has been deprecated, use Ext.dom.Element.mask &amp; Ext.dom.Element.unmask');
  105. }
  106. //&lt;/debug&gt;
  107. comp = Ext.get(comp);
  108. this.isElement = true;
  109. }
  110. me.ownerCt = comp;
  111. if (!this.isElement) {
  112. me.bindComponent(comp);
  113. }
  114. me.callParent([config]);
  115. if (me.store) {
  116. me.bindStore(me.store, true);
  117. }
  118. },
  119. bindComponent: function(comp){
  120. var me = this,
  121. listeners = {
  122. scope: this,
  123. resize: me.sizeMask,
  124. added: me.onComponentAdded,
  125. removed: me.onComponentRemoved
  126. },
  127. hierarchyEventSource = Ext.container.Container.hierarchyEventSource;
  128. if (comp.floating) {
  129. listeners.move = me.sizeMask;
  130. me.activeOwner = comp;
  131. } else if (comp.ownerCt) {
  132. me.onComponentAdded(comp.ownerCt);
  133. } else {
  134. // if the target comp is non-floating and under a floating comp don't bring the load mask to the front of the stack
  135. me.preventBringToFront = true;
  136. }
  137. me.mon(comp, listeners);
  138. // subscribe to the observer that manages the hierarchy
  139. me.mon(hierarchyEventSource, {
  140. show: me.onContainerShow,
  141. hide: me.onContainerHide,
  142. expand: me.onContainerExpand,
  143. collapse: me.onContainerCollapse,
  144. scope: me
  145. });
  146. },
  147. onComponentAdded: function(owner){
  148. var me = this;
  149. delete me.activeOwner;
  150. me.floatParent = owner;
  151. if (!owner.floating) {
  152. owner = owner.up('[floating]');
  153. }
  154. if (owner) {
  155. me.activeOwner = owner;
  156. me.mon(owner, 'move', me.sizeMask, me);
  157. }
  158. owner = me.floatParent.ownerCt;
  159. if (me.rendered &amp;&amp; me.isVisible() &amp;&amp; owner) {
  160. me.floatOwner = owner;
  161. me.mon(owner, 'afterlayout', me.sizeMask, me, {single: true});
  162. }
  163. },
  164. onComponentRemoved: function(owner){
  165. var me = this,
  166. activeOwner = me.activeOwner,
  167. floatOwner = me.floatOwner;
  168. if (activeOwner) {
  169. me.mun(activeOwner, 'move', me.sizeMask, me);
  170. }
  171. if (floatOwner) {
  172. me.mun(floatOwner, 'afterlayout', me.sizeMask, me);
  173. }
  174. delete me.activeOwner;
  175. delete me.floatOwner;
  176. },
  177. afterRender: function() {
  178. this.callParent(arguments);
  179. this.container = this.floatParent.getContentTarget();
  180. },
  181. onContainerShow: function(container){
  182. if (this.isActiveContainer(container)) {
  183. this.onComponentShow();
  184. }
  185. },
  186. onContainerHide: function(container){
  187. if (this.isActiveContainer(container)) {
  188. this.onComponentHide();
  189. }
  190. },
  191. onContainerExpand: function(container){
  192. if (this.isActiveContainer(container)) {
  193. this.onComponentShow();
  194. }
  195. },
  196. onContainerCollapse: function(container){
  197. if (this.isActiveContainer(container)) {
  198. this.onComponentHide();
  199. }
  200. },
  201. isActiveContainer: function(container){
  202. return this.isDescendantOf(container);
  203. },
  204. onComponentHide: function(){
  205. var me = this;
  206. if (me.rendered &amp;&amp; me.isVisible()) {
  207. me.hide();
  208. me.showNext = true;
  209. }
  210. },
  211. onComponentShow: function(){
  212. if (this.showNext) {
  213. this.show();
  214. }
  215. delete this.showNext;
  216. },
  217. <span id='Ext-LoadMask-method-sizeMask'> /**
  218. </span> * @private
  219. * Called when this LoadMask's Component is resized. The toFront method rebases and resizes the modal mask.
  220. */
  221. sizeMask: function() {
  222. var me = this,
  223. target;
  224. if (me.rendered &amp;&amp; me.isVisible()) {
  225. me.center();
  226. target = me.getMaskTarget();
  227. me.getMaskEl().show().setSize(target.getSize()).alignTo(target, 'tl-tl');
  228. }
  229. },
  230. <span id='Ext-LoadMask-method-bindStore'> /**
  231. </span> * Changes the data store bound to this LoadMask.
  232. * @param {Ext.data.Store} store The store to bind to this LoadMask
  233. */
  234. bindStore : function(store, initial) {
  235. var me = this;
  236. me.mixins.bindable.bindStore.apply(me, arguments);
  237. store = me.store;
  238. if (store &amp;&amp; store.isLoading()) {
  239. me.onBeforeLoad();
  240. }
  241. },
  242. getStoreListeners: function(){
  243. return {
  244. beforeload: this.onBeforeLoad,
  245. load: this.onLoad,
  246. exception: this.onLoad,
  247. // Fired when a range is requested for rendering that is not in the cache
  248. cachemiss: this.onBeforeLoad,
  249. // Fired when a range for rendering which was previously missing from the cache is loaded
  250. cachefilled: this.onLoad
  251. };
  252. },
  253. onDisable : function() {
  254. this.callParent(arguments);
  255. if (this.loading) {
  256. this.onLoad();
  257. }
  258. },
  259. getOwner: function(){
  260. return this.ownerCt || this.floatParent;
  261. },
  262. getMaskTarget: function(){
  263. var owner = this.getOwner();
  264. return this.useTargetEl ? owner.getTargetEl() : owner.getEl();
  265. },
  266. // private
  267. onBeforeLoad : function() {
  268. var me = this,
  269. owner = me.getOwner(),
  270. origin;
  271. if (!me.disabled) {
  272. me.loading = true;
  273. // If the owning Component has not been layed out, defer so that the ZIndexManager
  274. // gets to read its layed out size when sizing the modal mask
  275. if (owner.componentLayoutCounter) {
  276. me.maybeShow();
  277. } else {
  278. // The code below is a 'run-once' interceptor.
  279. origin = owner.afterComponentLayout;
  280. owner.afterComponentLayout = function() {
  281. owner.afterComponentLayout = origin;
  282. origin.apply(owner, arguments);
  283. me.maybeShow();
  284. };
  285. }
  286. }
  287. },
  288. maybeShow: function(){
  289. var me = this,
  290. owner = me.getOwner();
  291. if (!owner.isVisible(true)) {
  292. me.showNext = true;
  293. }
  294. else if (me.loading &amp;&amp; owner.rendered) {
  295. me.show();
  296. }
  297. },
  298. getMaskEl: function(){
  299. var me = this;
  300. return me.maskEl || (me.maskEl = me.el.insertSibling({
  301. cls: me.maskCls,
  302. style: {
  303. zIndex: me.el.getStyle('zIndex') - 2
  304. }
  305. }, 'before'));
  306. },
  307. onShow: function() {
  308. var me = this,
  309. msgEl = me.msgEl;
  310. me.callParent(arguments);
  311. me.loading = true;
  312. if (me.useMsg) {
  313. msgEl.show().update(me.msg);
  314. } else {
  315. msgEl.parent().hide();
  316. }
  317. },
  318. hide: function(){
  319. // Element support to be deprecated
  320. if (this.isElement) {
  321. this.ownerCt.unmask();
  322. this.fireEvent('hide', this);
  323. return;
  324. }
  325. delete this.showNext;
  326. return this.callParent(arguments);
  327. },
  328. onHide: function(){
  329. this.callParent();
  330. this.getMaskEl().hide();
  331. },
  332. show: function(){
  333. // Element support to be deprecated
  334. if (this.isElement) {
  335. this.ownerCt.mask(this.useMsg ? this.msg : '', this.msgCls);
  336. this.fireEvent('show', this);
  337. return;
  338. }
  339. return this.callParent(arguments);
  340. },
  341. afterShow: function() {
  342. this.callParent(arguments);
  343. this.sizeMask();
  344. },
  345. setZIndex: function(index) {
  346. var me = this,
  347. owner = me.activeOwner;
  348. if (owner) {
  349. // it seems silly to add 1 to have it subtracted in the call below,
  350. // but this allows the x-mask el to have the correct z-index (same as the component)
  351. // so instead of directly changing the zIndexStack just get the z-index of the owner comp
  352. index = parseInt(owner.el.getStyle('zIndex'), 10) + 1;
  353. }
  354. me.getMaskEl().setStyle('zIndex', index - 1);
  355. return me.mixins.floating.setZIndex.apply(me, arguments);
  356. },
  357. // private
  358. onLoad : function() {
  359. this.loading = false;
  360. this.hide();
  361. },
  362. onDestroy: function(){
  363. var me = this;
  364. if (me.isElement) {
  365. me.ownerCt.unmask();
  366. }
  367. Ext.destroy(me.maskEl);
  368. me.callParent();
  369. }
  370. });
  371. </pre>
  372. </body>
  373. </html>