]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * @private\r | |
3 | * Base class for iOS and Android viewports.\r | |
4 | */\r | |
5 | Ext.define('Ext.viewport.Default', {\r | |
6 | extend: 'Ext.Container',\r | |
7 | \r | |
8 | xtype: 'viewport',\r | |
9 | \r | |
10 | PORTRAIT: 'portrait',\r | |
11 | \r | |
12 | LANDSCAPE: 'landscape',\r | |
13 | \r | |
14 | requires: [\r | |
15 | 'Ext.GlobalEvents',\r | |
16 | 'Ext.LoadMask',\r | |
17 | 'Ext.layout.Card',\r | |
18 | 'Ext.util.InputBlocker'\r | |
19 | ],\r | |
20 | \r | |
21 | /**\r | |
22 | * @event ready\r | |
23 | * Fires when the Viewport is in the DOM and ready.\r | |
24 | * @param {Ext.Viewport} this\r | |
25 | */\r | |
26 | \r | |
27 | /**\r | |
28 | * @event maximize\r | |
29 | * Fires when the Viewport is maximized.\r | |
30 | * @param {Ext.Viewport} this\r | |
31 | */\r | |
32 | \r | |
33 | /**\r | |
34 | * @event orientationchange\r | |
35 | * Fires when the Viewport orientation has changed.\r | |
36 | * @param {Ext.Viewport} this\r | |
37 | * @param {String} newOrientation The new orientation.\r | |
38 | * @param {Number} width The width of the Viewport.\r | |
39 | * @param {Number} height The height of the Viewport.\r | |
40 | */\r | |
41 | \r | |
42 | config: {\r | |
43 | /**\r | |
44 | * @private\r | |
45 | */\r | |
46 | autoMaximize: false,\r | |
47 | \r | |
48 | /**\r | |
49 | * @private\r | |
50 | *\r | |
51 | * Auto blur the focused element when touching on a non-input. This is used to work around Android bugs\r | |
52 | * where the virtual keyboard is not hidden when tapping outside an input.\r | |
53 | */\r | |
54 | autoBlurInput: true,\r | |
55 | \r | |
56 | /**\r | |
57 | * @cfg {Boolean} preventPanning\r | |
58 | * Whether or not to always prevent default panning behavior of the\r | |
59 | * browser's viewport.\r | |
60 | * @accessor\r | |
61 | */\r | |
62 | preventPanning: true,\r | |
63 | \r | |
64 | /**\r | |
65 | * @cfg {Boolean} preventZooming\r | |
66 | * `true` to attempt to stop zooming when you double tap on the screen on mobile devices,\r | |
67 | * typically HTC devices with HTC Sense UI.\r | |
68 | * @accessor\r | |
69 | */\r | |
70 | preventZooming: false,\r | |
71 | \r | |
72 | /**\r | |
73 | * @cfg\r | |
74 | * @private\r | |
75 | */\r | |
76 | autoRender: true,\r | |
77 | \r | |
78 | /**\r | |
79 | * @cfg {Object/String} layout Configuration for this Container's layout. Example:\r | |
80 | *\r | |
81 | * Ext.create('Ext.Container', {\r | |
82 | * layout: {\r | |
83 | * type: 'hbox',\r | |
84 | * align: 'middle'\r | |
85 | * },\r | |
86 | * items: [\r | |
87 | * {\r | |
88 | * xtype: 'panel',\r | |
89 | * flex: 1,\r | |
90 | * style: 'background-color: red;'\r | |
91 | * },\r | |
92 | * {\r | |
93 | * xtype: 'panel',\r | |
94 | * flex: 2,\r | |
95 | * style: 'background-color: green'\r | |
96 | * }\r | |
97 | * ]\r | |
98 | * });\r | |
99 | *\r | |
100 | * See the [layouts guide](#!/guides/layouts) for more information.\r | |
101 | *\r | |
102 | * @accessor\r | |
103 | */\r | |
104 | layout: 'card',\r | |
105 | \r | |
106 | /**\r | |
107 | * @cfg\r | |
108 | * @private\r | |
109 | */\r | |
110 | width: '100%',\r | |
111 | \r | |
112 | /**\r | |
113 | * @cfg\r | |
114 | * @private\r | |
115 | */\r | |
116 | height: '100%',\r | |
117 | \r | |
118 | useBodyElement: true,\r | |
119 | \r | |
120 | /**\r | |
121 | * An object of all the menus on this viewport.\r | |
122 | * @private\r | |
123 | */\r | |
124 | menus: {}\r | |
125 | },\r | |
126 | \r | |
127 | /**\r | |
128 | * @property {Boolean} isReady\r | |
129 | * `true` if the DOM is ready.\r | |
130 | */\r | |
131 | isReady: false,\r | |
132 | \r | |
133 | isViewport: true,\r | |
134 | \r | |
135 | isMaximizing: false,\r | |
136 | \r | |
137 | id: 'ext-viewport',\r | |
138 | \r | |
139 | isInputRegex: /^(input|textarea|select|a)$/i,\r | |
140 | \r | |
141 | isInteractiveWebComponentRegEx: /^(audio|video)$/i,\r | |
142 | \r | |
143 | focusedElement: null,\r | |
144 | \r | |
145 | /**\r | |
146 | * @private\r | |
147 | */\r | |
148 | fullscreenItemCls: Ext.baseCSSPrefix + 'fullscreen',\r | |
149 | \r | |
150 | constructor: function(config) {\r | |
151 | var me = this,\r | |
152 | bind = Ext.Function.bind,\r | |
153 | Component = Ext.Component,\r | |
154 | DomScroller = Ext.scroll.DomScroller;\r | |
155 | \r | |
156 | // By default document.body is monitored by a special DomScroller singleton so that\r | |
157 | // the global scroll event fires when the document scrolls.\r | |
158 | // A Viewport's Scroller will take over from this one.\r | |
159 | if (DomScroller.document) {\r | |
160 | DomScroller.document = DomScroller.document.destroy();\r | |
161 | }\r | |
162 | \r | |
163 | me.doPreventPanning = bind(me.doPreventPanning, me);\r | |
164 | me.doPreventZooming = bind(me.doPreventZooming, me);\r | |
165 | me.doBlurInput = bind(me.doBlurInput, me);\r | |
166 | \r | |
167 | me.maximizeOnEvents = [\r | |
168 | 'ready',\r | |
169 | 'orientationchange'\r | |
170 | ];\r | |
171 | \r | |
172 | // set default devicePixelRatio if it is not explicitly defined\r | |
173 | window.devicePixelRatio = window.devicePixelRatio || 1;\r | |
174 | \r | |
175 | me.callParent([config]);\r | |
176 | \r | |
177 | me.orientation = me.determineOrientation();\r | |
178 | me.windowWidth = me.getWindowWidth();\r | |
179 | me.windowHeight = me.getWindowHeight();\r | |
180 | me.windowOuterHeight = me.getWindowOuterHeight();\r | |
181 | \r | |
182 | me.stretchHeights = me.stretchHeights || {};\r | |
183 | \r | |
184 | // Android is handled separately\r | |
185 | if (!Ext.os.is.Android || Ext.browser.is.ChromeMobile) {\r | |
186 | if (me.supportsOrientation()) {\r | |
187 | me.addWindowListener('orientationchange', bind(me.onOrientationChange, me));\r | |
188 | } else {\r | |
189 | me.addWindowListener('resize', bind(me.onResize, me));\r | |
190 | }\r | |
191 | }\r | |
192 | \r | |
193 | document.addEventListener('focus', bind(me.onElementFocus, me), true);\r | |
194 | document.addEventListener('blur', bind(me.onElementBlur, me), true);\r | |
195 | \r | |
196 | Ext.onDocumentReady(me.onDomReady, me);\r | |
197 | \r | |
198 | if (!Component.on) {\r | |
199 | Ext.util.Observable.observe(Component);\r | |
200 | }\r | |
201 | \r | |
202 | Component.on('fullscreen', 'onItemFullscreenChange', me);\r | |
203 | \r | |
204 | return me;\r | |
205 | },\r | |
206 | \r | |
207 | initialize: function() {\r | |
208 | var me = this;\r | |
209 | \r | |
210 | me.addMeta('apple-mobile-web-app-capable', 'yes');\r | |
211 | me.addMeta('apple-touch-fullscreen', 'yes');\r | |
212 | \r | |
213 | me.callParent();\r | |
214 | },\r | |
215 | \r | |
216 | initInheritedState: function (inheritedState, inheritedStateInner) {\r | |
217 | var me = this,\r | |
218 | root = Ext.rootInheritedState;\r | |
219 | \r | |
220 | if (inheritedState !== root) {\r | |
221 | // We need to go at this again but with the rootInheritedState object. Let\r | |
222 | // any derived class poke on the proper object!\r | |
223 | me.initInheritedState(me.inheritedState = root,\r | |
224 | me.inheritedStateInner = Ext.Object.chain(root));\r | |
225 | } else {\r | |
226 | me.callParent([inheritedState, inheritedStateInner]);\r | |
227 | }\r | |
228 | },\r | |
229 | \r | |
230 | onAppLaunch: function() {\r | |
231 | var me = this;\r | |
232 | if (!me.isReady) {\r | |
233 | me.onDomReady();\r | |
234 | }\r | |
235 | },\r | |
236 | \r | |
237 | onDomReady: function() {\r | |
238 | var me = this;\r | |
239 | \r | |
240 | if (me.isReady) {\r | |
241 | return;\r | |
242 | }\r | |
243 | \r | |
244 | me.isReady = true;\r | |
245 | me.updateSize();\r | |
246 | me.onReady();\r | |
247 | me.fireEvent('ready', me);\r | |
248 | Ext.GlobalEvents.fireEvent('viewportready', me);\r | |
249 | },\r | |
250 | \r | |
251 | onReady: function() {\r | |
252 | if (this.getAutoRender()) {\r | |
253 | this.render();\r | |
254 | }\r | |
255 | if (Ext.browser.name === 'ChromeiOS') {\r | |
256 | this.setHeight('-webkit-calc(100% - ' + ((window.outerHeight - window.innerHeight) / 2) + 'px)');\r | |
257 | }\r | |
258 | },\r | |
259 | \r | |
260 | onElementFocus: function(e) {\r | |
261 | this.focusedElement = e.target;\r | |
262 | },\r | |
263 | \r | |
264 | onElementBlur: function() {\r | |
265 | this.focusedElement = null;\r | |
266 | },\r | |
267 | \r | |
268 | render: function() {\r | |
269 | if (!this.rendered) {\r | |
270 | var body = Ext.getBody(),\r | |
271 | clsPrefix = Ext.baseCSSPrefix,\r | |
272 | classList = [],\r | |
273 | osEnv = Ext.os,\r | |
274 | osName = osEnv.name.toLowerCase(),\r | |
275 | browserName = Ext.browser.name.toLowerCase(),\r | |
276 | osMajorVersion = osEnv.version.getMajor(),\r | |
277 | orientation = this.getOrientation(),\r | |
278 | theme;\r | |
279 | \r | |
280 | this.renderTo(body);\r | |
281 | \r | |
282 | classList.push(clsPrefix + osEnv.deviceType.toLowerCase());\r | |
283 | \r | |
284 | if (osEnv.is.iPad) {\r | |
285 | classList.push(clsPrefix + 'ipad');\r | |
286 | }\r | |
287 | \r | |
288 | classList.push(clsPrefix + osName);\r | |
289 | classList.push(clsPrefix + browserName);\r | |
290 | \r | |
291 | if (osMajorVersion) {\r | |
292 | classList.push(clsPrefix + osName + '-' + osMajorVersion);\r | |
293 | }\r | |
294 | \r | |
295 | if (osEnv.is.BlackBerry) {\r | |
296 | classList.push(clsPrefix + 'bb');\r | |
297 | if (Ext.browser.userAgent.match(/Kbd/gi)) {\r | |
298 | classList.push(clsPrefix + 'bb-keyboard');\r | |
299 | }\r | |
300 | }\r | |
301 | \r | |
302 | if (Ext.browser.is.WebKit) {\r | |
303 | classList.push(clsPrefix + 'webkit');\r | |
304 | }\r | |
305 | \r | |
306 | if (Ext.browser.is.Standalone) {\r | |
307 | classList.push(clsPrefix + 'standalone');\r | |
308 | }\r | |
309 | \r | |
310 | if (Ext.browser.is.AndroidStock) {\r | |
311 | classList.push(clsPrefix + 'android-stock');\r | |
312 | }\r | |
313 | \r | |
314 | if (Ext.browser.is.GoogleGlass) {\r | |
315 | classList.push(clsPrefix + 'google-glass');\r | |
316 | }\r | |
317 | \r | |
318 | classList.push(clsPrefix + orientation);\r | |
319 | \r | |
320 | body.addCls(classList);\r | |
321 | \r | |
322 | theme = Ext.theme;\r | |
323 | if (theme && theme.getDocCls) {\r | |
324 | // hook for theme overrides to add css classes to the <html> element\r | |
325 | Ext.fly(document.documentElement).addCls(theme.getDocCls());\r | |
326 | }\r | |
327 | }\r | |
328 | },\r | |
329 | \r | |
330 | updateAutoBlurInput: function(autoBlurInput) {\r | |
331 | var touchstart = Ext.feature.has.TouchEvents ? 'touchstart' : 'mousedown';\r | |
332 | this.toggleWindowListener(autoBlurInput, touchstart, this.doBlurInput, false);\r | |
333 | },\r | |
334 | \r | |
335 | applyAutoMaximize: function(autoMaximize) {\r | |
336 | return Ext.browser.is.WebView ? false : autoMaximize;\r | |
337 | },\r | |
338 | \r | |
339 | updateAutoMaximize: function(autoMaximize) {\r | |
340 | var me = this;\r | |
341 | \r | |
342 | if (autoMaximize) {\r | |
343 | me.on('ready', 'doAutoMaximizeOnReady', me, { single: true });\r | |
344 | me.on('orientationchange', 'doAutoMaximizeOnOrientationChange', me);\r | |
345 | } else {\r | |
346 | me.un('ready', 'doAutoMaximizeOnReady', me);\r | |
347 | me.un('orientationchange', 'doAutoMaximizeOnOrientationChange', me);\r | |
348 | }\r | |
349 | },\r | |
350 | \r | |
351 | updatePreventPanning: function(preventPanning) {\r | |
352 | this.toggleWindowListener(preventPanning, 'touchmove', this.doPreventPanning, false);\r | |
353 | },\r | |
354 | \r | |
355 | updatePreventZooming: function(preventZooming) {\r | |
356 | var touchstart = Ext.feature.has.TouchEvents ? 'touchstart' : 'mousedown';\r | |
357 | this.toggleWindowListener(preventZooming, touchstart, this.doPreventZooming, false);\r | |
358 | },\r | |
359 | \r | |
360 | doAutoMaximizeOnReady: function() {\r | |
361 | var me = this;\r | |
362 | \r | |
363 | me.isMaximizing = true;\r | |
364 | \r | |
365 | me.on('maximize', function() {\r | |
366 | me.isMaximizing = false;\r | |
367 | \r | |
368 | me.updateSize();\r | |
369 | \r | |
370 | me.fireEvent('ready', me);\r | |
371 | }, me, { single: true });\r | |
372 | \r | |
373 | me.maximize();\r | |
374 | },\r | |
375 | \r | |
376 | doAutoMaximizeOnOrientationChange: function() {\r | |
377 | var me = this;\r | |
378 | \r | |
379 | me.isMaximizing = true;\r | |
380 | \r | |
381 | me.on('maximize', function() {\r | |
382 | me.isMaximizing = false;\r | |
383 | \r | |
384 | me.updateSize();\r | |
385 | }, me, { single: true });\r | |
386 | \r | |
387 | me.maximize();\r | |
388 | },\r | |
389 | \r | |
390 | doBlurInput: function(e) {\r | |
391 | var target = e.target,\r | |
392 | focusedElement = this.focusedElement;\r | |
393 | //In IE9/10 browser window loses focus and becomes inactive if focused element is <body>. So we shouldn't call blur for <body>\r | |
394 | // In FF, the focusedElement can be the document which doesn't have a blur method\r | |
395 | if (focusedElement && focusedElement.blur && focusedElement.nodeName.toUpperCase() != 'BODY' && !this.isInputRegex.test(target.tagName)) {\r | |
396 | delete this.focusedElement;\r | |
397 | focusedElement.blur();\r | |
398 | }\r | |
399 | },\r | |
400 | \r | |
401 | doPreventPanning: function(e) {\r | |
402 | var target = e.target, \r | |
403 | touch;\r | |
404 | \r | |
405 | // If we have an interaction on a WebComponent we need to check the actual shadow dom element selected\r | |
406 | // to determine if it is an input before preventing default behavior\r | |
407 | // Side effect to this is if the shadow input does not do anything with 'touchmove' the user could pan\r | |
408 | // the screen.\r | |
409 | if (this.isInteractiveWebComponentRegEx.test(target.tagName) && e.touches && e.touches.length > 0) {\r | |
410 | touch = e.touches[0];\r | |
411 | if (touch && touch.target && this.isInputRegex.test(touch.target.tagName)) {\r | |
412 | return;\r | |
413 | }\r | |
414 | }\r | |
415 | \r | |
416 | if (target && target.nodeType === 1 && !this.isInputRegex.test(target.tagName)) {\r | |
417 | e.preventDefault();\r | |
418 | }\r | |
419 | },\r | |
420 | \r | |
421 | doPreventZooming: function(e) {\r | |
422 | // Don't prevent right mouse event\r | |
423 | if ('button' in e && e.button !== 0) {\r | |
424 | return;\r | |
425 | }\r | |
426 | \r | |
427 | var target = e.target, \r | |
428 | inputRe = this.isInputRegex,\r | |
429 | touch;\r | |
430 | \r | |
431 | if (this.isInteractiveWebComponentRegEx.test(target.tagName) && e.touches && e.touches.length > 0) {\r | |
432 | touch = e.touches[0];\r | |
433 | if (touch && touch.target && inputRe.test(touch.target.tagName)) {\r | |
434 | return;\r | |
435 | }\r | |
436 | }\r | |
437 | \r | |
438 | if (target && target.nodeType === 1 && !inputRe.test(target.tagName)) {\r | |
439 | e.preventDefault();\r | |
440 | }\r | |
441 | },\r | |
442 | \r | |
443 | addWindowListener: function(eventName, fn, capturing) {\r | |
444 | window.addEventListener(eventName, fn, Boolean(capturing));\r | |
445 | },\r | |
446 | \r | |
447 | removeWindowListener: function(eventName, fn, capturing) {\r | |
448 | window.removeEventListener(eventName, fn, Boolean(capturing));\r | |
449 | },\r | |
450 | \r | |
451 | supportsOrientation: function() {\r | |
452 | return Ext.feature.has.Orientation;\r | |
453 | },\r | |
454 | \r | |
455 | onResize: function() {\r | |
456 | var me = this,\r | |
457 | oldWidth = me.windowWidth,\r | |
458 | oldHeight = me.windowHeight,\r | |
459 | width = me.getWindowWidth(),\r | |
460 | height = me.getWindowHeight(),\r | |
461 | currentOrientation = me.getOrientation(),\r | |
462 | newOrientation = me.determineOrientation();\r | |
463 | \r | |
464 | // Determine orientation change via resize. BOTH width AND height much change, otherwise\r | |
465 | // this is a keyboard popping up.\r | |
466 | if ((oldWidth !== width && oldHeight !== height) && currentOrientation !== newOrientation) {\r | |
467 | me.fireOrientationChangeEvent(newOrientation, currentOrientation);\r | |
468 | }\r | |
469 | },\r | |
470 | \r | |
471 | onOrientationChange: function() {\r | |
472 | var currentOrientation = this.getOrientation(),\r | |
473 | newOrientation = this.determineOrientation();\r | |
474 | \r | |
475 | if (newOrientation !== currentOrientation) {\r | |
476 | this.fireOrientationChangeEvent(newOrientation, currentOrientation);\r | |
477 | }\r | |
478 | },\r | |
479 | \r | |
480 | fireOrientationChangeEvent: function(newOrientation, oldOrientation) {\r | |
481 | var me = this,\r | |
482 | clsPrefix = Ext.baseCSSPrefix;\r | |
483 | \r | |
484 | Ext.getBody().replaceCls(clsPrefix + oldOrientation, clsPrefix + newOrientation);\r | |
485 | \r | |
486 | me.orientation = newOrientation;\r | |
487 | \r | |
488 | me.updateSize();\r | |
489 | me.fireEvent('orientationchange', me, newOrientation, me.windowWidth, me.windowHeight);\r | |
490 | },\r | |
491 | \r | |
492 | updateSize: function(width, height) {\r | |
493 | var me = this;\r | |
494 | \r | |
495 | me.windowWidth = width !== undefined ? width : me.getWindowWidth();\r | |
496 | me.windowHeight = height !== undefined ? height : me.getWindowHeight();\r | |
497 | \r | |
498 | return me;\r | |
499 | },\r | |
500 | \r | |
501 | waitUntil: function(condition, onSatisfied, onTimeout, delay, timeoutDuration) {\r | |
502 | if (!delay) {\r | |
503 | delay = 50;\r | |
504 | }\r | |
505 | \r | |
506 | if (!timeoutDuration) {\r | |
507 | timeoutDuration = 2000;\r | |
508 | }\r | |
509 | \r | |
510 | var scope = this,\r | |
511 | elapse = 0;\r | |
512 | \r | |
513 | Ext.defer(function repeat() {\r | |
514 | elapse += delay;\r | |
515 | \r | |
516 | if (condition.call(scope) === true) {\r | |
517 | if (onSatisfied) {\r | |
518 | onSatisfied.call(scope);\r | |
519 | }\r | |
520 | }\r | |
521 | else {\r | |
522 | if (elapse >= timeoutDuration) {\r | |
523 | if (onTimeout) {\r | |
524 | onTimeout.call(scope);\r | |
525 | }\r | |
526 | }\r | |
527 | else {\r | |
528 | Ext.defer(repeat, delay);\r | |
529 | }\r | |
530 | }\r | |
531 | }, delay);\r | |
532 | },\r | |
533 | \r | |
534 | maximize: function() {\r | |
535 | this.fireMaximizeEvent();\r | |
536 | },\r | |
537 | \r | |
538 | fireMaximizeEvent: function() {\r | |
539 | this.updateSize();\r | |
540 | this.fireEvent('maximize', this);\r | |
541 | },\r | |
542 | \r | |
543 | updateHeight: function(height, oldHeight) {\r | |
544 | Ext.getBody().setHeight(height);\r | |
545 | this.callParent([height, oldHeight]);\r | |
546 | },\r | |
547 | \r | |
548 | updateWidth: function(width, oldWidth) {\r | |
549 | Ext.getBody().setWidth(width);\r | |
550 | this.callParent([width, oldWidth]);\r | |
551 | },\r | |
552 | \r | |
553 | scrollToTop: function() {\r | |
554 | window.scrollTo(0, -1);\r | |
555 | },\r | |
556 | \r | |
557 | /**\r | |
558 | * Retrieves the document width.\r | |
559 | * @return {Number} width in pixels.\r | |
560 | */\r | |
561 | getWindowWidth: function() {\r | |
562 | return window.innerWidth;\r | |
563 | },\r | |
564 | \r | |
565 | /**\r | |
566 | * Retrieves the document height.\r | |
567 | * @return {Number} height in pixels.\r | |
568 | */\r | |
569 | getWindowHeight: function() {\r | |
570 | return window.innerHeight;\r | |
571 | },\r | |
572 | \r | |
573 | getWindowOuterHeight: function() {\r | |
574 | return window.outerHeight;\r | |
575 | },\r | |
576 | \r | |
577 | getWindowOrientation: function() {\r | |
578 | return window.orientation;\r | |
579 | },\r | |
580 | \r | |
581 | /**\r | |
582 | * Returns the current orientation.\r | |
583 | * @return {String} `portrait` or `landscape`\r | |
584 | */\r | |
585 | getOrientation: function() {\r | |
586 | return this.orientation;\r | |
587 | },\r | |
588 | \r | |
589 | getSize: function() {\r | |
590 | return {\r | |
591 | width: this.windowWidth,\r | |
592 | height: this.windowHeight\r | |
593 | };\r | |
594 | },\r | |
595 | \r | |
596 | determineOrientation: function() {\r | |
597 | var me = this,\r | |
598 | portrait = me.PORTRAIT,\r | |
599 | landscape = me.LANDSCAPE;\r | |
600 | \r | |
601 | if (!Ext.os.is.Android && me.supportsOrientation()) {\r | |
602 | if (me.getWindowOrientation() % 180 === 0) {\r | |
603 | return portrait;\r | |
604 | }\r | |
605 | \r | |
606 | return landscape;\r | |
607 | }\r | |
608 | else {\r | |
609 | if (me.getWindowHeight() >= me.getWindowWidth()) {\r | |
610 | return portrait;\r | |
611 | }\r | |
612 | \r | |
613 | return landscape;\r | |
614 | }\r | |
615 | },\r | |
616 | \r | |
617 | onItemFullscreenChange: function(item) {\r | |
618 | item.addCls(this.fullscreenItemCls);\r | |
619 | this.add(item);\r | |
620 | },\r | |
621 | \r | |
622 | /**\r | |
623 | * Sets a menu for a given side of the Viewport.\r | |
624 | *\r | |
625 | * Adds functionality to show the menu by swiping from the side of the screen from the given side.\r | |
626 | *\r | |
627 | * If a menu is already set for a given side, it will be removed.\r | |
628 | *\r | |
629 | * Available sides are: `left`, `right`, `top`, and `bottom`.\r | |
630 | *\r | |
631 | * @param {Ext.Menu/Object} menu The menu instance or config to assign to the viewport.\r | |
632 | * @param {Object} config The configuration for the menu.\r | |
633 | * @param {String} config.side The side to put the menu on.\r | |
634 | * @param {Boolean} config.cover True to cover the viewport content. Defaults to `true`.\r | |
635 | *\r | |
636 | * @return {Ext.Menu} The menu.\r | |
637 | */\r | |
638 | setMenu: function(menu, config) {\r | |
639 | config = config || {};\r | |
640 | \r | |
641 | var me = this,\r | |
642 | side = config.side,\r | |
643 | menus;\r | |
644 | \r | |
645 | // Temporary workaround for body shifting issue\r | |
646 | if (Ext.os.is.iOS && !me.hasiOSOrientationFix) {\r | |
647 | me.hasiOSOrientationFix = true;\r | |
648 | me.on('orientationchange', function() {\r | |
649 | window.scrollTo(0, 0);\r | |
650 | }, me);\r | |
651 | }\r | |
652 | \r | |
653 | //<debug>\r | |
654 | if (!menu) {\r | |
655 | Ext.Logger.error("You must specify a side to dock the menu.");\r | |
656 | }\r | |
657 | \r | |
658 | if (!side) {\r | |
659 | Ext.Logger.error("You must specify a side to dock the menu.");\r | |
660 | }\r | |
661 | \r | |
662 | if (['left', 'right', 'top', 'bottom'].indexOf(side) == -1) {\r | |
663 | Ext.Logger.error("You must specify a valid side (left, right, top or botom) to dock the menu.");\r | |
664 | }\r | |
665 | //</debug>\r | |
666 | \r | |
667 | menus = me.getMenus();\r | |
668 | \r | |
669 | if (!menus) {\r | |
670 | menus = {};\r | |
671 | }\r | |
672 | \r | |
673 | if (!me.addedSwipeListener) {\r | |
674 | me.attachSwipeListeners();\r | |
675 | me.addedSwipeListener = true;\r | |
676 | }\r | |
677 | \r | |
678 | // If we have a menu cfg and no type was passed, we need to\r | |
679 | // setup the type. This template method exists to defer\r | |
680 | // for subclasses\r | |
681 | if (!menu.isComponent) {\r | |
682 | if (!menu.xclass && !menu.xtype) {\r | |
683 | menu = me.getMenuCfg(menu, side);\r | |
684 | }\r | |
685 | menu = Ext.create(menu);\r | |
686 | }\r | |
687 | \r | |
688 | menus[side] = menu;\r | |
689 | menu.$reveal = Boolean(config.reveal);\r | |
690 | menu.$cover = config.cover !== false && !menu.$reveal;\r | |
691 | menu.$side = side;\r | |
692 | \r | |
693 | me.fixMenuSize(menu, side);\r | |
694 | \r | |
695 | if (side == 'left') {\r | |
696 | menu.setLeft(0);\r | |
697 | menu.setRight(null);\r | |
698 | menu.setTop(0);\r | |
699 | menu.setBottom(0);\r | |
700 | } else if (side == 'right') {\r | |
701 | menu.setLeft(null);\r | |
702 | menu.setRight(0);\r | |
703 | menu.setTop(0);\r | |
704 | menu.setBottom(0);\r | |
705 | } else if (side == 'top') {\r | |
706 | menu.setLeft(0);\r | |
707 | menu.setRight(0);\r | |
708 | menu.setTop(0);\r | |
709 | menu.setBottom(null);\r | |
710 | } else if (side == 'bottom') {\r | |
711 | menu.setLeft(0);\r | |
712 | menu.setRight(0);\r | |
713 | menu.setTop(null);\r | |
714 | menu.setBottom(0);\r | |
715 | }\r | |
716 | \r | |
717 | me.setMenus(menus);\r | |
718 | \r | |
719 | return menu;\r | |
720 | },\r | |
721 | \r | |
722 | attachSwipeListeners: function() {\r | |
723 | var me = this;\r | |
724 | \r | |
725 | me.element.on({\r | |
726 | tap: me.onTap,\r | |
727 | swipestart: me.onSwipeStart,\r | |
728 | edgeswipestart: me.onEdgeSwipeStart,\r | |
729 | edgeswipe: me.onEdgeSwipe,\r | |
730 | edgeswipeend: me.onEdgeSwipeEnd,\r | |
731 | scope: me\r | |
732 | });\r | |
733 | },\r | |
734 | \r | |
735 | getMenuCfg: function(menu, side) {\r | |
736 | return Ext.apply({\r | |
737 | xtype: 'menu'\r | |
738 | }, menu);\r | |
739 | },\r | |
740 | \r | |
741 | /**\r | |
742 | * Removes a menu from a specified side.\r | |
743 | * @param {String} side The side to remove the menu from\r | |
744 | */\r | |
745 | removeMenu: function(side) {\r | |
746 | var menus = this.getMenus() || {},\r | |
747 | menu = menus[side];\r | |
748 | \r | |
749 | if (menu) {\r | |
750 | this.hideMenu(side);\r | |
751 | }\r | |
752 | delete menus[side];\r | |
753 | this.setMenus(menus);\r | |
754 | },\r | |
755 | \r | |
756 | /**\r | |
757 | * @private\r | |
758 | * Changes the sizing of the specified menu so that it displays correctly when shown.\r | |
759 | */\r | |
760 | fixMenuSize: function(menu, side) {\r | |
761 | if (side == 'top' || side == 'bottom') {\r | |
762 | menu.setWidth('100%');\r | |
763 | } else if (side == 'left' || side == 'right') {\r | |
764 | menu.setHeight('100%');\r | |
765 | }\r | |
766 | },\r | |
767 | \r | |
768 | /**\r | |
769 | * Shows a menu specified by the menu's side.\r | |
770 | * @param {String} side The side which the menu is placed.\r | |
771 | */\r | |
772 | showMenu: function(side) {\r | |
773 | var me = this,\r | |
774 | menus = me.getMenus(),\r | |
775 | menu = menus[side],\r | |
776 | before, after,\r | |
777 | viewportBefore, viewportAfter, size;\r | |
778 | \r | |
779 | if (!menu || menu.isAnimating) {\r | |
780 | return;\r | |
781 | }\r | |
782 | \r | |
783 | me.hideOtherMenus(side);\r | |
784 | \r | |
785 | before = {\r | |
786 | translateX: 0,\r | |
787 | translateY: 0\r | |
788 | };\r | |
789 | \r | |
790 | after = {\r | |
791 | translateX: 0,\r | |
792 | translateY: 0\r | |
793 | };\r | |
794 | \r | |
795 | viewportBefore = {\r | |
796 | translateX: 0,\r | |
797 | translateY: 0\r | |
798 | };\r | |
799 | \r | |
800 | viewportAfter = {\r | |
801 | translateX: 0,\r | |
802 | translateY: 0\r | |
803 | };\r | |
804 | \r | |
805 | if (menu.$reveal) {\r | |
806 | Ext.getBody().insertFirst(menu.element);\r | |
807 | } else {\r | |
808 | Ext.Viewport.add(menu);\r | |
809 | }\r | |
810 | \r | |
811 | menu.show();\r | |
812 | menu.addCls('x-' + side);\r | |
813 | \r | |
814 | size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight();\r | |
815 | \r | |
816 | if (side == 'left') {\r | |
817 | before.translateX = -size;\r | |
818 | viewportAfter.translateX = size;\r | |
819 | } else if (side == 'right') {\r | |
820 | before.translateX = size;\r | |
821 | viewportAfter.translateX = -size;\r | |
822 | } else if (side == 'top') {\r | |
823 | before.translateY = -size;\r | |
824 | viewportAfter.translateY = size;\r | |
825 | } else if (side == 'bottom') {\r | |
826 | before.translateY = size;\r | |
827 | viewportAfter.translateY = -size;\r | |
828 | }\r | |
829 | \r | |
830 | if (menu.$reveal) {\r | |
831 | if (Ext.browser.getPreferredTranslationMethod() != 'scrollposition') {\r | |
832 | menu.translate(0, 0);\r | |
833 | }\r | |
834 | } else {\r | |
835 | menu.translate(before.translateX, before.translateY);\r | |
836 | }\r | |
837 | \r | |
838 | if (menu.$cover) {\r | |
839 | menu.getTranslatable().on('animationend', function() {\r | |
840 | menu.isAnimating = false;\r | |
841 | }, me, {\r | |
842 | single: true\r | |
843 | });\r | |
844 | \r | |
845 | menu.translate(after.translateX, after.translateY, {\r | |
846 | preserveEndState: true,\r | |
847 | duration: 200\r | |
848 | });\r | |
849 | \r | |
850 | } else {\r | |
851 | me.translate(viewportBefore.translateX, viewportBefore.translateY);\r | |
852 | \r | |
853 | \r | |
854 | me.getTranslatable().on('animationend', function() {\r | |
855 | menu.isAnimating = false;\r | |
856 | }, me, {\r | |
857 | single: true\r | |
858 | });\r | |
859 | \r | |
860 | me.translate(viewportAfter.translateX, viewportAfter.translateY, {\r | |
861 | preserveEndState: true,\r | |
862 | duration: 200\r | |
863 | });\r | |
864 | }\r | |
865 | \r | |
866 | // Make the menu as animating\r | |
867 | menu.isAnimating = true;\r | |
868 | },\r | |
869 | \r | |
870 | /**\r | |
871 | * Hides a menu specified by the menu's side.\r | |
872 | * @param {String} side The side which the menu is placed.\r | |
873 | */\r | |
874 | hideMenu: function(side, animate) {\r | |
875 | var me = this,\r | |
876 | menus = this.getMenus(),\r | |
877 | menu = menus[side],\r | |
878 | after, viewportAfter,\r | |
879 | size;\r | |
880 | \r | |
881 | animate = animate !== false;\r | |
882 | \r | |
883 | if (!menu || (menu.isHidden() || menu.isAnimating)) {\r | |
884 | return;\r | |
885 | }\r | |
886 | \r | |
887 | after = {\r | |
888 | translateX: 0,\r | |
889 | translateY: 0\r | |
890 | };\r | |
891 | \r | |
892 | viewportAfter = {\r | |
893 | translateX: 0,\r | |
894 | translateY: 0\r | |
895 | };\r | |
896 | \r | |
897 | size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight();\r | |
898 | \r | |
899 | if (side == 'left') {\r | |
900 | after.translateX = -size;\r | |
901 | } else if (side == 'right') {\r | |
902 | after.translateX = size;\r | |
903 | } else if (side == 'top') {\r | |
904 | after.translateY = -size;\r | |
905 | } else if (side == 'bottom') {\r | |
906 | after.translateY = size;\r | |
907 | }\r | |
908 | \r | |
909 | if (menu.$cover) {\r | |
910 | if (animate) {\r | |
911 | menu.getTranslatable().on('animationend', function() {\r | |
912 | menu.isAnimating = false;\r | |
913 | menu.hide();\r | |
914 | }, me, {\r | |
915 | single: true\r | |
916 | });\r | |
917 | \r | |
918 | menu.translate(after.translateX, after.translateY, {\r | |
919 | preserveEndState: true,\r | |
920 | duration: 200\r | |
921 | });\r | |
922 | } else {\r | |
923 | menu.translate(after.translateX, after.translateY);\r | |
924 | menu.hide()\r | |
925 | }\r | |
926 | } else {\r | |
927 | if (animate) {\r | |
928 | me.getTranslatable().on('animationend', function() {\r | |
929 | menu.isAnimating = false;\r | |
930 | menu.hide();\r | |
931 | }, me, {\r | |
932 | single: true\r | |
933 | });\r | |
934 | \r | |
935 | me.translate(viewportAfter.translateX, viewportAfter.translateY, {\r | |
936 | preserveEndState: true,\r | |
937 | duration: 200\r | |
938 | });\r | |
939 | } else {\r | |
940 | me.translate(viewportAfter.translateX, viewportAfter.translateY);\r | |
941 | menu.hide();\r | |
942 | }\r | |
943 | }\r | |
944 | },\r | |
945 | \r | |
946 | /**\r | |
947 | * Hides all visible menus.\r | |
948 | */\r | |
949 | hideAllMenus: function(animation) {\r | |
950 | var menus = this.getMenus(),\r | |
951 | side;\r | |
952 | \r | |
953 | for (side in menus) {\r | |
954 | this.hideMenu(side, animation);\r | |
955 | }\r | |
956 | },\r | |
957 | \r | |
958 | /**\r | |
959 | * Hides all menus except for the side specified\r | |
960 | * @param {String} side Side(s) not to hide\r | |
961 | * @param {String} animation Animation to hide with\r | |
962 | */\r | |
963 | hideOtherMenus: function(side, animation){\r | |
964 | var menus = this.getMenus(),\r | |
965 | menu;\r | |
966 | \r | |
967 | for (menu in menus) {\r | |
968 | if (side !== menu) {\r | |
969 | this.hideMenu(menu, animation);\r | |
970 | }\r | |
971 | }\r | |
972 | },\r | |
973 | \r | |
974 | /**\r | |
975 | * Toggles the menu specified by side\r | |
976 | * @param {String} side The side which the menu is placed.\r | |
977 | */\r | |
978 | toggleMenu: function(side) {\r | |
979 | var menus = this.getMenus(), \r | |
980 | menu;\r | |
981 | \r | |
982 | if (menus[side]) {\r | |
983 | menu = menus[side];\r | |
984 | if (menu.isHidden()) {\r | |
985 | this.showMenu(side);\r | |
986 | } else {\r | |
987 | this.hideMenu(side);\r | |
988 | }\r | |
989 | }\r | |
990 | },\r | |
991 | \r | |
992 | /**\r | |
993 | * @private\r | |
994 | */\r | |
995 | sideForDirection: function(direction) {\r | |
996 | if (direction === 'left') {\r | |
997 | return 'right';\r | |
998 | } else if (direction === 'right') {\r | |
999 | return 'left';\r | |
1000 | } else if (direction == 'up') {\r | |
1001 | return 'bottom';\r | |
1002 | } else if (direction == 'down') {\r | |
1003 | return 'top';\r | |
1004 | }\r | |
1005 | },\r | |
1006 | \r | |
1007 | /**\r | |
1008 | * @private\r | |
1009 | */\r | |
1010 | sideForSwipeDirection: function(direction) {\r | |
1011 | if (direction == 'up') {\r | |
1012 | return 'top';\r | |
1013 | } else if (direction == 'down') {\r | |
1014 | return 'bottom';\r | |
1015 | }\r | |
1016 | return direction;\r | |
1017 | },\r | |
1018 | \r | |
1019 | /**\r | |
1020 | * @private\r | |
1021 | */\r | |
1022 | onTap: function(e) {\r | |
1023 | // this.hideAllMenus();\r | |
1024 | },\r | |
1025 | \r | |
1026 | /**\r | |
1027 | * @private\r | |
1028 | */\r | |
1029 | onSwipeStart: function(e) {\r | |
1030 | var side = this.sideForSwipeDirection(e.direction);\r | |
1031 | this.hideMenu(side);\r | |
1032 | },\r | |
1033 | \r | |
1034 | /**\r | |
1035 | * @private\r | |
1036 | */\r | |
1037 | onEdgeSwipeStart: function(e) {\r | |
1038 | var me = this,\r | |
1039 | side = me.sideForDirection(e.direction),\r | |
1040 | menus = me.getMenus(),\r | |
1041 | menu = menus[side],\r | |
1042 | menuSide, checkMenu, size,\r | |
1043 | after, viewportAfter,\r | |
1044 | transformStyleName, setTransform;\r | |
1045 | \r | |
1046 | if (!menu || !menu.isHidden()) {\r | |
1047 | return;\r | |
1048 | }\r | |
1049 | \r | |
1050 | for (menuSide in menus) {\r | |
1051 | checkMenu = menus[menuSide];\r | |
1052 | if (checkMenu.isHidden() !== false) {\r | |
1053 | return;\r | |
1054 | }\r | |
1055 | }\r | |
1056 | \r | |
1057 | me.$swiping = true;\r | |
1058 | \r | |
1059 | me.hideAllMenus(false);\r | |
1060 | \r | |
1061 | // show the menu first so we can calculate the size\r | |
1062 | if (menu.$reveal) {\r | |
1063 | Ext.getBody().insertFirst(menu.element);\r | |
1064 | } else {\r | |
1065 | Ext.Viewport.add(menu);\r | |
1066 | }\r | |
1067 | menu.show();\r | |
1068 | \r | |
1069 | size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight();\r | |
1070 | \r | |
1071 | after = {\r | |
1072 | translateX: 0,\r | |
1073 | translateY: 0\r | |
1074 | };\r | |
1075 | \r | |
1076 | viewportAfter = {\r | |
1077 | translateX: 0,\r | |
1078 | translateY: 0\r | |
1079 | };\r | |
1080 | \r | |
1081 | if (side == 'left') {\r | |
1082 | after.translateX = -size;\r | |
1083 | } else if (side == 'right') {\r | |
1084 | after.translateX = size;\r | |
1085 | } else if (side == 'top') {\r | |
1086 | after.translateY = -size;\r | |
1087 | } else if (side == 'bottom') {\r | |
1088 | after.translateY = size;\r | |
1089 | }\r | |
1090 | \r | |
1091 | transformStyleName = 'webkitTransform' in document.createElement('div').style ? 'webkitTransform' : 'transform';\r | |
1092 | setTransform = menu.element.dom.style[transformStyleName];\r | |
1093 | \r | |
1094 | if (setTransform) {\r | |
1095 | menu.element.dom.style[transformStyleName] = '';\r | |
1096 | }\r | |
1097 | \r | |
1098 | if (menu.$reveal) {\r | |
1099 | if (Ext.browser.getPreferredTranslationMethod() != 'scrollposition') {\r | |
1100 | menu.translate(0, 0);\r | |
1101 | }\r | |
1102 | } else {\r | |
1103 | menu.translate(after.translateX, after.translateY);\r | |
1104 | }\r | |
1105 | \r | |
1106 | if (!menu.$cover) {\r | |
1107 | if (setTransform) {\r | |
1108 | me.innerElement.dom.style[transformStyleName] = '';\r | |
1109 | }\r | |
1110 | \r | |
1111 | me.translate(viewportAfter.translateX, viewportAfter.translateY);\r | |
1112 | }\r | |
1113 | },\r | |
1114 | \r | |
1115 | /**\r | |
1116 | * @private\r | |
1117 | */\r | |
1118 | onEdgeSwipe: function(e) {\r | |
1119 | var me = this,\r | |
1120 | side = me.sideForDirection(e.direction),\r | |
1121 | menu = me.getMenus()[side],\r | |
1122 | size, after, viewportAfter,\r | |
1123 | movement, viewportMovement;\r | |
1124 | \r | |
1125 | if (!menu || !me.$swiping) {\r | |
1126 | return;\r | |
1127 | }\r | |
1128 | \r | |
1129 | size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight();\r | |
1130 | movement = Math.min(e.distance - size, 0);\r | |
1131 | viewportMovement = Math.min(e.distance, size);\r | |
1132 | \r | |
1133 | after = {\r | |
1134 | translateX: 0,\r | |
1135 | translateY: 0\r | |
1136 | };\r | |
1137 | \r | |
1138 | viewportAfter = {\r | |
1139 | translateX: 0,\r | |
1140 | translateY: 0\r | |
1141 | };\r | |
1142 | \r | |
1143 | if (side == 'left') {\r | |
1144 | after.translateX = movement;\r | |
1145 | viewportAfter.translateX = viewportMovement;\r | |
1146 | } else if (side == 'right') {\r | |
1147 | after.translateX = -movement;\r | |
1148 | viewportAfter.translateX = -viewportMovement;\r | |
1149 | } else if (side == 'top') {\r | |
1150 | after.translateY = movement;\r | |
1151 | viewportAfter.translateY = viewportMovement;\r | |
1152 | } else if (side == 'bottom') {\r | |
1153 | after.translateY = -movement;\r | |
1154 | viewportAfter.translateY = -viewportMovement;\r | |
1155 | }\r | |
1156 | \r | |
1157 | if (menu.$cover) {\r | |
1158 | menu.translate(after.translateX, after.translateY);\r | |
1159 | } else {\r | |
1160 | me.translate(viewportAfter.translateX, viewportAfter.translateY);\r | |
1161 | }\r | |
1162 | },\r | |
1163 | \r | |
1164 | /**\r | |
1165 | * @private\r | |
1166 | */\r | |
1167 | onEdgeSwipeEnd: function(e) {\r | |
1168 | var me = this,\r | |
1169 | side = me.sideForDirection(e.direction),\r | |
1170 | menu = me.getMenus()[side],\r | |
1171 | shouldRevert = false,\r | |
1172 | size, velocity, movement, viewportMovement,\r | |
1173 | after, viewportAfter;\r | |
1174 | \r | |
1175 | if (!menu) {\r | |
1176 | return;\r | |
1177 | }\r | |
1178 | \r | |
1179 | size = (side == 'left' || side == 'right') ? menu.element.getWidth() : menu.element.getHeight();\r | |
1180 | velocity = (e.flick) ? e.flick.velocity : 0;\r | |
1181 | \r | |
1182 | // check if continuing in the right direction\r | |
1183 | if (side == 'right') {\r | |
1184 | if (velocity.x > 0) {\r | |
1185 | shouldRevert = true;\r | |
1186 | }\r | |
1187 | } else if (side == 'left') {\r | |
1188 | if (velocity.x < 0) {\r | |
1189 | shouldRevert = true;\r | |
1190 | }\r | |
1191 | } else if (side == 'top') {\r | |
1192 | if (velocity.y < 0) {\r | |
1193 | shouldRevert = true;\r | |
1194 | }\r | |
1195 | } else if (side == 'bottom') {\r | |
1196 | if (velocity.y > 0) {\r | |
1197 | shouldRevert = true;\r | |
1198 | }\r | |
1199 | }\r | |
1200 | \r | |
1201 | movement = shouldRevert ? size : 0;\r | |
1202 | viewportMovement = shouldRevert ? 0 : -size;\r | |
1203 | \r | |
1204 | after = {\r | |
1205 | translateX: 0,\r | |
1206 | translateY: 0\r | |
1207 | };\r | |
1208 | \r | |
1209 | viewportAfter = {\r | |
1210 | translateX: 0,\r | |
1211 | translateY: 0\r | |
1212 | };\r | |
1213 | \r | |
1214 | if (side == 'left') {\r | |
1215 | after.translateX = -movement;\r | |
1216 | viewportAfter.translateX = -viewportMovement;\r | |
1217 | } else if (side == 'right') {\r | |
1218 | after.translateX = movement;\r | |
1219 | viewportAfter.translateX = viewportMovement;\r | |
1220 | } else if (side == 'top') {\r | |
1221 | after.translateY = -movement;\r | |
1222 | viewportAfter.translateY = -viewportMovement;\r | |
1223 | } else if (side == 'bottom') {\r | |
1224 | after.translateY = movement;\r | |
1225 | viewportAfter.translateY = viewportMovement;\r | |
1226 | }\r | |
1227 | \r | |
1228 | // Move the viewport if cover is not enabled\r | |
1229 | if (menu.$cover) {\r | |
1230 | menu.getTranslatable().on('animationend', function() {\r | |
1231 | if (shouldRevert) {\r | |
1232 | menu.hide();\r | |
1233 | }\r | |
1234 | }, me, {\r | |
1235 | single: true\r | |
1236 | });\r | |
1237 | \r | |
1238 | menu.translate(after.translateX, after.translateY, {\r | |
1239 | preserveEndState: true,\r | |
1240 | duration: 200\r | |
1241 | });\r | |
1242 | \r | |
1243 | } else {\r | |
1244 | me.getTranslatable().on('animationend', function() {\r | |
1245 | if (shouldRevert) {\r | |
1246 | menu.hide();\r | |
1247 | }\r | |
1248 | }, me, {\r | |
1249 | single: true\r | |
1250 | });\r | |
1251 | \r | |
1252 | me.translate(viewportAfter.translateX, viewportAfter.translateY, {\r | |
1253 | preserveEndState: true,\r | |
1254 | duration: 200\r | |
1255 | });\r | |
1256 | }\r | |
1257 | \r | |
1258 | me.$swiping = false;\r | |
1259 | },\r | |
1260 | \r | |
1261 | privates: {\r | |
1262 | addMeta: function(name, content) {\r | |
1263 | var meta = document.createElement('meta');\r | |
1264 | \r | |
1265 | meta.setAttribute('name', name);\r | |
1266 | meta.setAttribute('content', content);\r | |
1267 | Ext.getHead().append(meta);\r | |
1268 | },\r | |
1269 | \r | |
1270 | doAddListener: function(eventName, fn, scope, options, order, caller, manager) {\r | |
1271 | var me = this;\r | |
1272 | if (eventName === 'ready' && me.isReady && !me.isMaximizing) {\r | |
1273 | fn.call(scope);\r | |
1274 | return me;\r | |
1275 | }\r | |
1276 | \r | |
1277 | me.callParent([eventName, fn, scope, options, order, caller, manager]);\r | |
1278 | },\r | |
1279 | \r | |
1280 | toggleWindowListener: function(on, eventName, fn, capturing) {\r | |
1281 | if (on) {\r | |
1282 | this.addWindowListener(eventName, fn, capturing);\r | |
1283 | } else {\r | |
1284 | this.removeWindowListener(eventName, fn, capturing);\r | |
1285 | }\r | |
1286 | }\r | |
1287 | }\r | |
1288 | });\r |