UNPKG

25.4 kBJavaScriptView Raw
1/*
2Copyright 2013-2015 ASIAL CORPORATION
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15
16*/
17
18import onsElements from '../ons/elements.js';
19import util from '../ons/util.js';
20import AnimatorFactory from '../ons/internal/animator-factory.js';
21import orientation from '../ons/orientation.js';
22import internal from '../ons/internal/index.js';
23import ModifierUtil from '../ons/internal/modifier-util.js';
24import BaseElement from './base/base-element.js';
25import SplitterAnimator from './ons-splitter/animator.js';
26import SwipeReveal from '../ons/internal/swipe-reveal.js';
27import DoorLock from '../ons/doorlock.js';
28import contentReady from '../ons/content-ready.js';
29import { PageLoader, defaultPageLoader} from '../ons/page-loader.js';
30import SplitterElement from './ons-splitter.js';
31
32const SPLIT_MODE = 'split';
33const COLLAPSE_MODE = 'collapse';
34const CLOSED_STATE = 'closed';
35const OPEN_STATE = 'open';
36const CHANGING_STATE = 'changing';
37
38const rewritables = {
39 /**
40 * @param {Element} splitterSideElement
41 * @param {Function} callback
42 */
43 ready(splitterSideElement, callback) {
44 setImmediate(callback);
45 }
46};
47
48class CollapseDetection {
49 constructor(element, target) {
50 this._element = element;
51 this._onChange = this._onChange.bind(this);
52 target && this.changeTarget(target);
53 }
54
55 changeTarget(target) {
56 this.disable();
57 this._target = target;
58 if (target) {
59 this._orientation = ['portrait', 'landscape'].indexOf(target) !== -1;
60 this.activate();
61 }
62 }
63
64 _match(value) {
65 if (this._orientation) {
66 return this._target === (value.isPortrait ? 'portrait' : 'landscape');
67 }
68 return value.matches;
69 }
70
71 _onChange(value) {
72 this._element._updateMode(this._match(value) ? COLLAPSE_MODE : SPLIT_MODE);
73 }
74
75 activate() {
76 if (this._orientation) {
77 orientation.on('change', this._onChange);
78 this._onChange({isPortrait: orientation.isPortrait()});
79 } else {
80 this._queryResult = window.matchMedia(this._target);
81 this._queryResult.addListener(this._onChange);
82 this._onChange(this._queryResult);
83 }
84 }
85
86 disable() {
87 if (this._orientation) {
88 orientation.off('change', this._onChange);
89 } else if (this._queryResult) {
90 this._queryResult.removeListener(this._onChange);
91 this._queryResult = null;
92 }
93 }
94}
95
96const widthToPx = (width, parent) => {
97 const [value, px] = [parseInt(width, 10), /px/.test(width)];
98 return px ? value : Math.round(parent.offsetWidth * value / 100);
99};
100
101/**
102 * @element ons-splitter-side
103 * @category menu
104 * @description
105 * [en]
106 * The `<ons-splitter-side>` element is used as a child element of `<ons-splitter>`.
107 *
108 * It will be displayed on either the left or right side of the `<ons-splitter-content>` element.
109 *
110 * It supports two modes: collapsed and split. When it's in collapsed mode it will be hidden from view and can be displayed when the user swipes the screen or taps a button. In split mode the element is always shown. It can be configured to automatically switch between the two modes depending on the screen size.
111 * [/en]
112 * [ja]ons-splitter-side要素は、ons-splitter要素の子要素として利用します。[/ja]
113 * @codepen rOQOML
114 * @tutorial vanilla/Reference/splitter
115 * @guide fundamentals.html#managing-pages
116 * [en]Managing multiple pages.[/en]
117 * [ja]複数のページを管理する[/ja]
118 * @seealso ons-splitter
119 * [en]The `<ons-splitter>` is the parent component.[/en]
120 * [ja]ons-splitterコンポーネント[/ja]
121 * @seealso ons-splitter-content
122 * [en]The `<ons-splitter-content>` component contains the main content of the page.[/en]
123 * [ja]ons-splitter-contentコンポーネント[/ja]
124 * @example
125 * <ons-splitter>
126 * <ons-splitter-content>
127 * ...
128 * </ons-splitter-content>
129 *
130 * <ons-splitter-side side="left" width="80%" collapse>
131 * ...
132 * </ons-splitter-side>
133 * </ons-splitter>
134 */
135export default class SplitterSideElement extends BaseElement {
136
137 /**
138 * @event modechange
139 * @description
140 * [en]Fired just after the component's mode changes.[/en]
141 * [ja]この要素のモードが変化した際に発火します。[/ja]
142 * @param {Object} event
143 * [en]Event object.[/en]
144 * [ja]イベントオブジェクトです。[/ja]
145 * @param {Object} event.side
146 * [en]Component object.[/en]
147 * [ja]コンポーネントのオブジェクト。[/ja]
148 * @param {String} event.mode
149 * [en]Returns the current mode. Can be either `"collapse"` or `"split"`.[/en]
150 * [ja]現在のモードを返します。[/ja]
151 */
152
153 /**
154 * @event preopen
155 * @description
156 * [en]Fired just before the sliding menu is opened.[/en]
157 * [ja]スライディングメニューが開く前に発火します。[/ja]
158 * @param {Object} event
159 * [en]Event object.[/en]
160 * [ja]イベントオブジェクトです。[/ja]
161 * @param {Function} event.cancel
162 * [en]Call to cancel opening sliding menu.[/en]
163 * [ja]スライディングメニューが開くのをキャンセルします。[/ja]
164 * @param {Object} event.side
165 * [en]Component object.[/en]
166 * [ja]コンポーネントのオブジェクト。[/ja]
167 */
168
169 /**
170 * @event postopen
171 * @description
172 * [en]Fired just after the sliding menu is opened.[/en]
173 * [ja]スライディングメニューが開いた後に発火します。[/ja]
174 * @param {Object} event
175 * [en]Event object.[/en]
176 * [ja]イベントオブジェクトです。[/ja]
177 * @param {Object} event.side
178 * [en]Component object.[/en]
179 * [ja]コンポーネントのオブジェクト。[/ja]
180 */
181
182 /**
183 * @event preclose
184 * @description
185 * [en]Fired just before the sliding menu is closed.[/en]
186 * [ja]スライディングメニューが閉じる前に発火します。[/ja]
187 * @param {Object} event
188 * [en]Event object.[/en]
189 * [ja]イベントオブジェクトです。[/ja]
190 * @param {Object} event.side
191 * [en]Component object.[/en]
192 * [ja]コンポーネントのオブジェクト。[/ja]
193 * @param {Function} event.cancel
194 * [en]Call to cancel opening sliding-menu.[/en]
195 * [ja]スライディングメニューが閉じるのをキャンセルします。[/ja]
196 */
197
198 /**
199 * @event postclose
200 * @description
201 * [en]Fired just after the sliding menu is closed.[/en]
202 * [ja]スライディングメニューが閉じた後に発火します。[/ja]
203 * @param {Object} event
204 * [en]Event object.[/en]
205 * [ja]イベントオブジェクトです。[/ja]
206 * @param {Object} event.side
207 * [en]Component object.[/en]
208 * [ja]コンポーネントのオブジェクト。[/ja]
209 */
210
211 /**
212 * @event swipe
213 * @description
214 * [en]Fired whenever the user slides the splitter.[/en]
215 * [ja][/ja]
216 * @param {Object} event [en]Event object.[/en]
217 * @param {Object} event.ratio
218 * [en]Decimal ratio (0-1).[/en]
219 * [ja][/ja]
220 * @param {Object} event.animationOptions
221 * [en][/en]
222 * [ja][/ja]
223 */
224
225 /**
226 * @attribute animation
227 * @type {String}
228 * @default default
229 * @description
230 * [en]Specify the animation. Use one of `overlay`, `push`, `reveal` or `default`.[/en]
231 * [ja]アニメーションを指定します。"overlay", "push", "reveal", "default"のいずれかを指定できます。[/ja]
232 */
233
234 /**
235 * @attribute animation-options
236 * @type {Expression}
237 * @description
238 * [en]Specify the animation's duration, timing and delay with an object literal. E.g. `{duration: 0.2, delay: 1, timing: 'ease-in'}`.[/en]
239 * [ja]アニメーション時のduration, timing, delayをオブジェクトリテラルで指定します。e.g. {duration: 0.2, delay: 1, timing: 'ease-in'}[/ja]
240 */
241
242 /**
243 * @property animationOptions
244 * @type {Object}
245 * @description
246 * [en]Specify the animation's duration, timing and delay with an object literal. E.g. `{duration: 0.2, delay: 1, timing: 'ease-in'}`.[/en]
247 * [ja]アニメーション時のduration, timing, delayをオブジェクトリテラルで指定します。e.g. {duration: 0.2, delay: 1, timing: 'ease-in'}[/ja]
248 */
249
250 /**
251 * @attribute open-threshold
252 * @type {Number}
253 * @default 0.3
254 * @description
255 * [en]Specify how much the menu needs to be swiped before opening. A value between `0` and `1`.[/en]
256 * [ja]どのくらいスワイプすればスライディングメニューを開くかどうかの割合を指定します。0から1の間の数値を指定します。スワイプの距離がここで指定した数値掛けるこの要素の幅よりも大きければ、スワイプが終わった時にこの要素を開きます。デフォルトは0.3です。[/ja]
257 */
258
259 /**
260 * @attribute collapse
261 * @type {String}
262 * @description
263 * [en]
264 * Specify the collapse behavior. Valid values are `"portrait"`, `"landscape"` or a media query.
265 * The string `"portrait"` means the view will collapse when the device is in portrait orientation.
266 * The string `"landscape"` means the view will collapse when the device is in landscape orientation.
267 * If the value is a media query, the view will collapse when the media query resolves to `true`.
268 * If the attribute is set, including as an empty string, the view will always be in `"collapse"` mode.
269 * If the attribute is not set, the view will be in `"split"` mode.
270 * [/en]
271 * [ja]
272 * 左側のページを非表示にする条件を指定します。portrait, landscape、width #pxもしくはメディアクエリの指定が可能です。
273 * portraitもしくはlandscapeを指定すると、デバイスの画面が縦向きもしくは横向きになった時に適用されます。
274 * メディアクエリを指定すると、指定したクエリに適合している場合に適用されます。
275 * 値に何も指定しない場合には、常にcollapseモードになります。
276 * [/ja]
277 */
278
279 /**
280 * @attribute swipe-target-width
281 * @type {String}
282 * @description
283 * [en]The width of swipeable area calculated from the edge (in pixels). Use this to enable swipe only when the finger touch on the screen edge.[/en]
284 * [ja]スワイプの判定領域をピクセル単位で指定します。画面の端から指定した距離に達するとページが表示されます。[/ja]
285 */
286
287 /**
288 * @attribute width
289 * @type {String}
290 * @description
291 * [en]Can be specified in either pixels or as a percentage, e.g. `90%` or `200px`.[/en]
292 * [ja]この要素の横幅を指定します。pxと%での指定が可能です。eg. 90%, 200px[/ja]
293 */
294
295 /**
296 * @attribute side
297 * @type {String}
298 * @default left
299 * @description
300 * [en]Specify which side of the screen the `<ons-splitter-side>` element is located. Possible values are `"left"` and `"right"`.[/en]
301 * [ja]この要素が左か右かを指定します。指定できる値は"left"か"right"のみです。[/ja]
302 */
303
304 /**
305 * @attribute mode
306 * @type {String}
307 * @description
308 * [en]Current mode. Possible values are `"collapse"` or `"split"`. This attribute is read only.[/en]
309 * [ja]現在のモードが設定されます。"collapse"もしくは"split"が指定されます。この属性は読み込み専用です。[/ja]
310 */
311
312 /**
313 * @attribute page
314 * @initonly
315 * @type {String}
316 * @description
317 * [en]The URL of the menu page.[/en]
318 * [ja]ons-splitter-side要素に表示するページのURLを指定します。[/ja]
319 */
320
321 /**
322 * @attribute swipeable
323 * @type {Boolean}
324 * @description
325 * [en]Whether to enable swipe interaction on collapse mode.[/en]
326 * [ja]collapseモード時にスワイプ操作を有効にする場合に指定します。[/ja]
327 */
328
329 /**
330 * @property swipeable
331 * @type {Boolean}
332 * @description
333 * [en]Whether to enable swipe interaction on collapse mode.[/en]
334 * [ja]collapseモード時にスワイプ操作を有効にする場合に指定します。[/ja]
335 */
336
337 constructor() {
338 super();
339
340 this._page = null;
341 this._state = CLOSED_STATE;
342 this._lock = new DoorLock();
343 this._pageLoader = defaultPageLoader;
344 this._collapseDetection = new CollapseDetection(this);
345
346 this._animatorFactory = new AnimatorFactory({
347 animators: SplitterElement.animators,
348 baseClass: SplitterAnimator,
349 baseClassName: 'SplitterAnimator',
350 defaultAnimation: this.getAttribute('animation')
351 });
352
353 contentReady(this, () => {
354 // These attributes are used early by the parent element
355 this.attributeChangedCallback('width');
356 if (!this.hasAttribute('side')) {
357 this.setAttribute('side', 'left');
358 }
359
360 rewritables.ready(this, () => {
361 const page = this._page || this.getAttribute('page');
362 page && this.load(page);
363 });
364 });
365 }
366
367 connectedCallback() {
368 if (!util.match(this.parentNode, 'ons-splitter')) {
369 util.throw('Parent must be an ons-splitter element');
370 }
371
372 if (!this._swipe) {
373 this._swipe = new SwipeReveal({
374 element: this,
375 elementHandler: this.parentElement,
376 swipeMax: () => {
377 const ratio = 1;
378 this._onSwipe && this._onSwipe(ratio, this._animationOpt);
379 util.triggerElementEvent(this, 'swipe', { ratio, animationOptions: this._animationOpt });
380 this.open();
381 },
382 swipeMid: (distance, width) => {
383 const ratio = distance / width;
384 this._onSwipe && this._onSwipe(ratio);
385 util.triggerElementEvent(this, 'swipe', { ratio });
386 this._animator.translate(distance);
387 },
388 swipeMin: () => {
389 const ratio = 0;
390 this._onSwipe && this._onSwipe(ratio, this._animationOpt);
391 util.triggerElementEvent(this, 'swipe', { ratio, animationOptions: this._animationOpt });
392 this.close();
393 },
394 getThreshold: () => Math.max(0, Math.min(1, parseFloat(this.getAttribute('open-threshold')) || 0.3)),
395 getSide: () => this.side,
396 isInitialState: () => {
397 const closed = this._state === CLOSED_STATE;
398 this._state = CHANGING_STATE;
399 return closed;
400 },
401 ignoreSwipe: (event, distance) => {
402 const isOpen = this.isOpen;
403 const validDrag = d => this.side === 'left'
404 ? ((d === 'left' && isOpen) || (d === 'right' && !isOpen))
405 : ((d === 'left' && !isOpen) || (d === 'right' && isOpen));
406
407 const area = Math.max(0, parseInt(this.getAttribute('swipe-target-width'), 10) || 0);
408
409 return this._mode === SPLIT_MODE || this._lock.isLocked() || this._isOtherSideOpen()
410 || !validDrag(event.gesture.direction)
411 || (!isOpen && area !== 0 && distance > area);
412 }
413 });
414
415 this.attributeChangedCallback('swipeable');
416 }
417
418 contentReady(this, () => {
419 this.constructor.observedAttributes.forEach(attr => this.attributeChangedCallback(attr, null, this.getAttribute(attr)));
420 });
421 }
422
423 get side() {
424 return this.getAttribute('side') === 'right' ? 'right' : 'left';
425 }
426
427 set side(value) {
428 if (value) {
429 this.setAttribute('side', value);
430 } else {
431 tihs.removeAttribute('side');
432 }
433 }
434
435 disconnectedCallback() {
436 this._swipe && this._swipe.dispose();
437 this._animator = this._animationOpt = this._swipe = null;
438 }
439
440 static get observedAttributes() {
441 return ['animation', 'width', 'collapse', 'swipeable', 'animation-options'];
442 }
443
444 attributeChangedCallback(name, last, current) {
445 switch (name) {
446 case 'swipeable':
447 this._swipe && this._swipe.update();
448 break;
449 case 'width':
450 current = this.getAttribute('width'); // Sometimes undefined. CE bug?
451 this.style.width = /^\d+(px|%)$/.test(current) ? current : '80%';
452 break;
453 case 'animation':
454 case 'animation-options':
455 this._updateAnimation();
456 break;
457 default:
458 this[util.camelize(`_update-${name}`)](current);
459 }
460 }
461
462 _emitEvent(name) {
463 if (name.slice(0, 3) !== 'pre') {
464 return util.triggerElementEvent(this, name, {side: this});
465 }
466 let isCanceled = false;
467
468 util.triggerElementEvent(this, name, {
469 side: this,
470 cancel: () => isCanceled = true
471 });
472
473 return isCanceled;
474 }
475
476 _isOtherSideOpen() {
477 return !!util.findChild(this.parentElement,
478 el => el instanceof this.constructor && el !== this && el._mode === COLLAPSE_MODE && el.isOpen
479 );
480 }
481
482 _updateCollapse(value = this.getAttribute('collapse')) {
483 if (value === null || value === 'split') {
484 this._collapseDetection.disable();
485 return this._updateMode(SPLIT_MODE);
486 }
487 if (value === '' || value === 'collapse') {
488 this._collapseDetection.disable();
489 return this._updateMode(COLLAPSE_MODE);
490 }
491
492 this._collapseDetection.changeTarget(value);
493 }
494
495 _updateMode(mode) {
496 if (mode !== this._mode) {
497 this._mode = mode;
498 this.setAttribute('mode', mode); // readonly attribute for the users
499
500 if (mode === SPLIT_MODE) {
501 this._animator && this._animator.deactivate();
502 this._state = CLOSED_STATE;
503 } else {
504 this._animator && this._animator.activate(this);
505 this._state === OPEN_STATE && this._animator.open();
506 }
507
508 util.triggerElementEvent(this, 'modechange', { side: this, mode });
509 }
510 }
511
512 _updateAnimation(animation = this.getAttribute('animation')) {
513 if (this.parentNode) {
514 this._animator && this._animator.deactivate();
515 this._animator = this._animatorFactory.newAnimator({animation});
516 this._animator.activate(this);
517 this._animationOpt = {
518 timing: this._animator.duration,
519 duration: this._animator.duration
520 };
521 this._animator.updateOptions(this.animationOptions);
522 }
523 }
524
525 /**
526 * @property page
527 * @type {*}
528 * @description
529 * [en]Page location to load in the splitter side.[/en]
530 * [ja]この要素内に表示するページを指定します。[/ja]
531 */
532 get page() {
533 return this._page;
534 }
535
536 /**
537 * @param {*} page
538 */
539 set page(page) {
540 this._page = page;
541 }
542
543 get _content() {
544 return this.children[0];
545 }
546
547 /**
548 * @property pageLoader
549 * @description
550 * [en][/en]
551 * [ja][/ja]
552 */
553 get pageLoader() {
554 return this._pageLoader;
555 }
556
557 set pageLoader(loader) {
558 if (!(loader instanceof PageLoader)) {
559 util.throwPageLoader();
560 }
561 this._pageLoader = loader;
562 }
563
564 /**
565 * @property mode
566 * @readonly
567 * @type {String}
568 * @description
569 * [en]Current mode. Possible values are "split", "collapse", "closed", "open" or "changing".[/en]
570 * [ja][/ja]
571 */
572 get mode() {
573 return this._mode;
574 }
575
576 /**
577 * @property onSwipe
578 * @type {Function}
579 * @description
580 * [en]Hook called whenever the user slides the splitter. It gets a decimal ratio (0-1) and an animationOptions object as arguments.[/en]
581 * [ja][/ja]
582 */
583 get onSwipe() {
584 return this._onSwipe;
585 }
586
587 set onSwipe(value) {
588 if (value && !(value instanceof Function)) {
589 util.throw('"onSwipe" must be a function');
590 }
591 this._onSwipe = value;
592 }
593
594 get animationOptions() {
595 return this.hasAttribute('animation-options') ?
596 AnimatorFactory.parseAnimationOptionsString(this.getAttribute('animation-options')) : {};
597 }
598
599 set animationOptions(value) {
600 if (value === undefined || value === null) {
601 this.removeAttribute('animation-options');
602 } else {
603 this.setAttribute('animation-options', JSON.stringify(value));
604 }
605 }
606
607 /**
608 * @property isOpen
609 * @type {Boolean}
610 * @description
611 * [en]Specifies whether the menu is opened.[/en]
612 * [ja][/ja]
613 */
614 get isOpen() {
615 return this._mode === COLLAPSE_MODE && this._state !== CLOSED_STATE;
616 }
617
618 set isOpen(value) {
619 this.toggle({}, value);
620 }
621
622 /**
623 * @method open
624 * @signature open([options])
625 * @param {Object} [options]
626 * [en]Parameter object.[/en]
627 * [ja]オプションを指定するオブジェクト。[/ja]
628 * @param {Function} [options.callback]
629 * [en]This function will be called after the menu has been opened.[/en]
630 * [ja]メニューが開いた後に呼び出される関数オブジェクトを指定します。[/ja]
631 * @description
632 * [en]Open menu in collapse mode.[/en]
633 * [ja]collapseモードになっているons-splitter-side要素を開きます。[/ja]
634 * @return {Promise}
635 * [en]Resolves to the splitter side element or false if not in collapse mode[/en]
636 * [ja][/ja]
637 */
638 open(options) {
639 return this.toggle(options, true);
640 }
641
642 /**
643 * @method close
644 * @signature close([options])
645 * @param {Object} [options]
646 * [en]Parameter object.[/en]
647 * [ja]オプションを指定するオブジェクト。[/ja]
648 * @param {Function} [options.callback]
649 * [en]This function will be called after the menu has been closed.[/en]
650 * [ja]メニューが閉じた後に呼び出される関数オブジェクトを指定します。[/ja]
651 * @description
652 * [en]Close menu in collapse mode.[/en]
653 * [ja]collapseモードになっているons-splitter-side要素を閉じます。[/ja]
654 * @return {Promise}
655 * [en]Resolves to the splitter side element or false if not in collapse mode[/en]
656 * [ja][/ja]
657 */
658 close(options) {
659 return this.toggle(options, false);
660 }
661
662 /**
663 * @method toggle
664 * @signature toggle([options])
665 * @param {Object} [options]
666 * @description
667 * [en]Opens if it's closed. Closes if it's open.[/en]
668 * [ja]開けている場合は要素を閉じますそして開けている場合は要素を開きます。[/ja]
669 * @return {Promise}
670 * [en]Resolves to the splitter side element or false if not in collapse mode[/en]
671 * [ja][/ja]
672 */
673 toggle(options = {}, force) {
674 const shouldOpen = typeof force === 'boolean' ? force : !this.isOpen;
675 const action = shouldOpen ? 'open' : 'close';
676 const FINAL_STATE = shouldOpen ? OPEN_STATE : CLOSED_STATE;
677
678 if (this._mode === SPLIT_MODE) {
679 return Promise.resolve(false);
680 }
681 if (this._state === FINAL_STATE) {
682 return Promise.resolve(this);
683 }
684 if (this._lock.isLocked()) {
685 return Promise.reject('Another splitter-side action is already running.');
686 }
687 if (shouldOpen && this._isOtherSideOpen()) {
688 return Promise.reject('Another menu is already open.');
689 }
690 if (this._emitEvent(`pre${action}`)) {
691 return Promise.reject(`Canceled in pre${action} event.`);
692 }
693
694 const unlock = this._lock.lock();
695 this._state = CHANGING_STATE;
696
697 if (options.animation) {
698 this._updateAnimation(options.animation);
699 }
700
701 return new Promise(resolve => {
702 this._animator[action](() => {
703 util.iosPageScrollFix(shouldOpen);
704 this._state = FINAL_STATE;
705 unlock();
706 this._emitEvent(`post${action}`);
707 options.callback instanceof Function && options.callback(this);
708 resolve(this);
709 });
710 });
711 }
712
713 /**
714 * @method load
715 * @signature load(page, [options])
716 * @param {String} page
717 * [en]Page URL. Can be either an HTML document or a `<template>`.[/en]
718 * [ja]pageのURLか、`<template>`で宣言したテンプレートのid属性の値を指定します。[/ja]
719 * @param {Object} [options]
720 * @param {Function} [options.callback]
721 * @description
722 * [en]Show the page specified in pageUrl in the right section[/en]
723 * [ja]指定したURLをメインページを読み込みます。[/ja]
724 * @return {Promise}
725 * [en]Resolves to the new page element[/en]
726 * [ja][/ja]
727 */
728 load(page, options = {}) {
729 this._page = page;
730 const callback = options.callback || (() => {});
731
732 return new Promise(resolve => {
733 let oldContent = this._content || null;
734
735 this._pageLoader.load({page, parent: this}, pageElement => {
736 if (oldContent) {
737 this._pageLoader.unload(oldContent);
738 oldContent = null;
739 }
740
741 setImmediate(() => this._show());
742
743 callback(pageElement);
744 resolve(pageElement);
745 });
746 });
747 }
748
749 _show() {
750 if (this._content) {
751 this._content._show();
752 }
753 }
754
755 _hide() {
756 if (this._content) {
757 this._content._hide();
758 }
759 }
760
761 _destroy() {
762 if (this._content) {
763 this._pageLoader.unload(this._content);
764 }
765 this.remove();
766 }
767
768 static get events() {
769 return ['preopen', 'postopen', 'preclose', 'postclose', 'modechange', 'swipe'];
770 }
771
772 static get rewritables() {
773 return rewritables;
774 }
775}
776
777util.defineBooleanProperties(SplitterSideElement, ['swipeable']);
778
779onsElements.SplitterSide = SplitterSideElement;
780customElements.define('ons-splitter-side', SplitterSideElement);