123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
- import _createClass from 'babel-runtime/helpers/createClass';
- /*
- Copyright 2013-2015 ASIAL CORPORATION
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- */
-
- import platform from '../platform';
-
- var util = {
- _ready: false,
-
- _domContentLoaded: false,
-
- _onDOMContentLoaded: function _onDOMContentLoaded() {
- util._domContentLoaded = true;
-
- if (platform.isWebView()) {
- window.document.addEventListener('deviceready', function () {
- util._ready = true;
- }, false);
- } else {
- util._ready = true;
- }
- },
-
- addBackButtonListener: function addBackButtonListener(fn) {
- if (!this._domContentLoaded) {
- throw new Error('This method is available after DOMContentLoaded');
- }
-
- if (this._ready) {
- window.document.addEventListener('backbutton', fn, false);
- } else {
- window.document.addEventListener('deviceready', function () {
- window.document.addEventListener('backbutton', fn, false);
- });
- }
- },
-
- removeBackButtonListener: function removeBackButtonListener(fn) {
- if (!this._domContentLoaded) {
- throw new Error('This method is available after DOMContentLoaded');
- }
-
- if (this._ready) {
- window.document.removeEventListener('backbutton', fn, false);
- } else {
- window.document.addEventListener('deviceready', function () {
- window.document.removeEventListener('backbutton', fn, false);
- });
- }
- }
- };
- window.addEventListener('DOMContentLoaded', function () {
- return util._onDOMContentLoaded();
- }, false);
-
- var HandlerRepository = {
- _store: {},
-
- _genId: function () {
- var i = 0;
- return function () {
- return i++;
- };
- }(),
-
- set: function set(element, handler) {
- if (element.dataset.deviceBackButtonHandlerId) {
- this.remove(element);
- }
- var id = element.dataset.deviceBackButtonHandlerId = HandlerRepository._genId();
- this._store[id] = handler;
- },
-
- remove: function remove(element) {
- if (element.dataset.deviceBackButtonHandlerId) {
- delete this._store[element.dataset.deviceBackButtonHandlerId];
- delete element.dataset.deviceBackButtonHandlerId;
- }
- },
-
- get: function get(element) {
- if (!element.dataset.deviceBackButtonHandlerId) {
- return undefined;
- }
-
- var id = element.dataset.deviceBackButtonHandlerId;
-
- if (!this._store[id]) {
- throw new Error();
- }
-
- return this._store[id];
- },
-
- has: function has(element) {
- if (!element.dataset) {
- return false;
- }
-
- var id = element.dataset.deviceBackButtonHandlerId;
-
- return !!this._store[id];
- }
- };
-
- var DeviceBackButtonDispatcher = function () {
- function DeviceBackButtonDispatcher() {
- _classCallCheck(this, DeviceBackButtonDispatcher);
-
- this._isEnabled = false;
- this._boundCallback = this._callback.bind(this);
- }
-
- /**
- * Enable to handle 'backbutton' events.
- */
-
-
- _createClass(DeviceBackButtonDispatcher, [{
- key: 'enable',
- value: function enable() {
- if (!this._isEnabled) {
- util.addBackButtonListener(this._boundCallback);
- this._isEnabled = true;
- }
- }
-
- /**
- * Disable to handle 'backbutton' events.
- */
-
- }, {
- key: 'disable',
- value: function disable() {
- if (this._isEnabled) {
- util.removeBackButtonListener(this._boundCallback);
- this._isEnabled = false;
- }
- }
-
- /**
- * Fire a 'backbutton' event manually.
- */
-
- }, {
- key: 'fireDeviceBackButtonEvent',
- value: function fireDeviceBackButtonEvent() {
- var event = document.createEvent('Event');
- event.initEvent('backbutton', true, true);
- document.dispatchEvent(event);
- }
- }, {
- key: '_callback',
- value: function _callback() {
- this._dispatchDeviceBackButtonEvent();
- }
-
- /**
- * @param {HTMLElement} element
- * @param {Function} callback
- */
-
- }, {
- key: 'createHandler',
- value: function createHandler(element, callback) {
- if (!(element instanceof HTMLElement)) {
- throw new Error('element must be an instance of HTMLElement');
- }
-
- if (!(callback instanceof Function)) {
- throw new Error('callback must be an instance of Function');
- }
-
- var handler = {
- _callback: callback,
- _element: element,
-
- disable: function disable() {
- HandlerRepository.remove(element);
- },
-
- setListener: function setListener(callback) {
- this._callback = callback;
- },
-
- enable: function enable() {
- HandlerRepository.set(element, this);
- },
-
- isEnabled: function isEnabled() {
- return HandlerRepository.get(element) === this;
- },
-
- destroy: function destroy() {
- HandlerRepository.remove(element);
- this._callback = this._element = null;
- }
- };
-
- handler.enable();
-
- return handler;
- }
- }, {
- key: '_dispatchDeviceBackButtonEvent',
- value: function _dispatchDeviceBackButtonEvent() {
- var tree = this._captureTree();
-
- var element = this._findHandlerLeafElement(tree);
-
- var handler = HandlerRepository.get(element);
- handler._callback(createEvent(element));
-
- function createEvent(element) {
- return {
- _element: element,
- callParentHandler: function callParentHandler() {
- var parent = this._element.parentNode;
-
- while (parent) {
- handler = HandlerRepository.get(parent);
- if (handler) {
- return handler._callback(createEvent(parent));
- }
- parent = parent.parentNode;
- }
- }
- };
- }
- }
-
- /**
- * @return {Object}
- */
-
- }, {
- key: '_captureTree',
- value: function _captureTree() {
- return createTree(document.body);
-
- function createTree(element) {
- var tree = {
- element: element,
- children: Array.prototype.concat.apply([], arrayOf(element.children).map(function (childElement) {
-
- if (childElement.style.display === 'none' || childElement._isShown === false) {
- return [];
- }
-
- if (childElement.children.length === 0 && !HandlerRepository.has(childElement)) {
- return [];
- }
-
- var result = createTree(childElement);
-
- if (result.children.length === 0 && !HandlerRepository.has(result.element)) {
- return [];
- }
-
- return [result];
- }))
- };
-
- if (!HandlerRepository.has(tree.element)) {
- for (var i = 0; i < tree.children.length; i++) {
- var subTree = tree.children[i];
- if (HandlerRepository.has(subTree.element)) {
- return subTree;
- }
- }
- }
-
- return tree;
- }
-
- function arrayOf(target) {
- var result = [];
- for (var i = 0; i < target.length; i++) {
- result.push(target[i]);
- }
- return result;
- }
- }
-
- /**
- * @param {Object} tree
- * @return {HTMLElement}
- */
-
- }, {
- key: '_findHandlerLeafElement',
- value: function _findHandlerLeafElement(tree) {
- return find(tree);
-
- function find(node) {
- if (node.children.length === 0) {
- return node.element;
- }
-
- if (node.children.length === 1) {
- return find(node.children[0]);
- }
-
- return node.children.map(function (childNode) {
- return childNode.element;
- }).reduce(function (left, right) {
- if (!left) {
- return right;
- }
-
- var leftZ = parseInt(window.getComputedStyle(left, '').zIndex, 10);
- var rightZ = parseInt(window.getComputedStyle(right, '').zIndex, 10);
-
- if (!isNaN(leftZ) && !isNaN(rightZ)) {
- return leftZ > rightZ ? left : right;
- }
-
- throw new Error('Capturing backbutton-handler is failure.');
- }, null);
- }
- }
- }]);
-
- return DeviceBackButtonDispatcher;
- }();
-
- export default new DeviceBackButtonDispatcher();
|