Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
293
gaia/tv_apps/app-deck/bower_components/smart-modal-dialog/smart-modal-dialog.js
vendored
Executable file
293
gaia/tv_apps/app-deck/bower_components/smart-modal-dialog/smart-modal-dialog.js
vendored
Executable file
|
|
@ -0,0 +1,293 @@
|
|||
/**
|
||||
* SmartModalDialog creates a dialog with a group of buttons as select
|
||||
* options. It also includes open/close animation and bubbling animation.
|
||||
* The template is shown below:
|
||||
* <smart-dialog class="modal-dialog">
|
||||
* <div class="outer-container">
|
||||
* <div class="container">
|
||||
* <div class="modal-dialog-message-container">
|
||||
* <div class="modal-dialog-message"></div>
|
||||
* <div class="modal-dialog-custom-group"></div>
|
||||
* </div>
|
||||
* <div class="modal-dialog-button-group">
|
||||
* <smart-button></smart-button>
|
||||
* ...
|
||||
* <smart-button></smart-button>
|
||||
* </div>
|
||||
* </div>
|
||||
* </div>
|
||||
* </smart-dialog>
|
||||
*/
|
||||
|
||||
(function(exports) {
|
||||
'use strict';
|
||||
|
||||
var DEFAULT_MARGIN = 44;
|
||||
|
||||
function SmartModalDialog(container, options) {
|
||||
// Determine whether this dialog is opened or not
|
||||
this._clickedIndex = null;
|
||||
this.defaultFocusIndex = -1;
|
||||
|
||||
this._margin = options && options.margin ? options.margin : DEFAULT_MARGIN;
|
||||
this._translateX = 0;
|
||||
|
||||
BaseModalDialog.call(this, container);
|
||||
}
|
||||
|
||||
var proto = Object.create(BaseModalDialog.prototype);
|
||||
|
||||
proto._init = function() {
|
||||
this._render();
|
||||
|
||||
this.smartBubble = document.createElement('smart-bubbles');
|
||||
this.element.addEventListener('will-open', this);
|
||||
this.element.addEventListener('will-close', this);
|
||||
this.element.addEventListener('opened', this);
|
||||
this.element.addEventListener('closed', this);
|
||||
this.smartBubble.addEventListener('all-items-bubbled', this);
|
||||
};
|
||||
|
||||
proto._render = function() {
|
||||
this.messageElement = document.createElement('div');
|
||||
this.messageElement.classList.add('modal-dialog-message');
|
||||
|
||||
this.customElementGroup = document.createElement('div');
|
||||
this.customElementGroup.classList.add('modal-dialog-custom-group');
|
||||
|
||||
this.messageContainer = document.createElement('div');
|
||||
this.messageContainer.classList.add('modal-dialog-message-container');
|
||||
this.messageContainer.appendChild(this.messageElement);
|
||||
this.messageContainer.appendChild(this.customElementGroup);
|
||||
|
||||
this.buttonGroup = document.createElement('div');
|
||||
this.buttonGroup.classList.add('modal-dialog-button-group');
|
||||
this.buttonGroup.setAttribute('smart-bubbles', 'true');
|
||||
|
||||
this.innerContainer.appendChild(this.messageContainer);
|
||||
this.innerContainer.appendChild(this.buttonGroup);
|
||||
};
|
||||
|
||||
proto._renderMessage = function(options) {
|
||||
this.message = options.message || {};
|
||||
|
||||
this.customSettings = options.customElementSettings || null;
|
||||
if (this.customSettings) {
|
||||
while (this.customElementGroup.firstChild) {
|
||||
this.customElementGroup.removeChild(this.customElementGroup.firstChild);
|
||||
}
|
||||
this.customElementGroup.appendChild(this.customSettings.element);
|
||||
this.customElementGroup.classList.remove('hidden');
|
||||
} else {
|
||||
this.customElementGroup.classList.add('hidden');
|
||||
}
|
||||
|
||||
if (!this.message.textRaw && !this.message.textL10nId) {
|
||||
this.messageElement.classList.add('hidden');
|
||||
} else {
|
||||
this.messageElement.classList.remove('hidden');
|
||||
this.messageElement.textContent = this.message.textRaw || '';
|
||||
if (this.message.textL10nId) {
|
||||
this._setL10n(this.messageElement, this.message.textL10nId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
proto._renderButtons = function(options) {
|
||||
var renderedCallback = options.onButtonRendered;
|
||||
this.buttonElements = [];
|
||||
this.buttonSettings = options.buttonSettings || [];
|
||||
this.buttonGroup.innerHTML = '';
|
||||
|
||||
// Set up every button
|
||||
this.buttonSettings.forEach(function buildButton(buttonSetting, index) {
|
||||
var button = document.createElement('smart-button');
|
||||
button.setAttribute('type', buttonSetting.type || 'circle-text');
|
||||
button.textContent = buttonSetting.textRaw || 'OK';
|
||||
if (buttonSetting.textL10nId) {
|
||||
this._setL10n(button, buttonSetting.textL10nId);
|
||||
}
|
||||
button.classList.add(buttonSetting.class || 'confirm');
|
||||
if (buttonSetting.icon) {
|
||||
button.style.backgroundImage = 'url(' + buttonSetting.icon + ')';
|
||||
} else if (buttonSetting.iconFont) {
|
||||
button.dataset.icon = buttonSetting.iconFont;
|
||||
}
|
||||
button.addEventListener('click', function() {
|
||||
// Click action will be handled in closed event
|
||||
this._clickedIndex = index;
|
||||
this.element.close();
|
||||
this.element.focus();
|
||||
}.bind(this));
|
||||
this.buttonElements.push(button);
|
||||
this.buttonGroup.appendChild(button);
|
||||
this._focusedIndex =
|
||||
(buttonSetting.defaultFocus) ? index : this._focusedIndex;
|
||||
if (renderedCallback) {
|
||||
// We add render callback to let user to do more complex visual
|
||||
// modifications.
|
||||
renderedCallback(button, buttonSetting);
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
proto._open = function(options) {
|
||||
this._focusedIndex = this.defaultFocusIndex;
|
||||
this._renderMessage(options);
|
||||
this._renderButtons(options);
|
||||
BaseModalDialog.prototype._open.call(this, options);
|
||||
};
|
||||
|
||||
proto.startKeyNavigation = function() {
|
||||
this.element.addEventListener('keydown', this);
|
||||
if (this.buttonElements.length > 0) {
|
||||
if (this._focusedIndex === -1) {
|
||||
this._focusedIndex = 0;
|
||||
}
|
||||
this.focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll the list to the input element
|
||||
*/
|
||||
proto._scrollTo = function(element) {
|
||||
var newTransition = this._getScrollOffset(element);
|
||||
this._translateX = newTransition;
|
||||
this.buttonGroup.style.transform = 'translateX(' + this._translateX +
|
||||
'px)';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the offset of the node element
|
||||
*/
|
||||
proto._getScrollOffset = function(nodeElem) {
|
||||
if (!this._viewWidth) {
|
||||
this._viewWidth = this.innerContainer.clientWidth - 2 * this._margin;
|
||||
}
|
||||
var nodeLeft = nodeElem.offsetLeft;
|
||||
var nodeWidth = nodeElem.offsetWidth;
|
||||
var listWidth = this.buttonGroup.offsetWidth;
|
||||
var newTranslate = this._translateX;
|
||||
var lastElement = this.buttonElements[this.buttonElements.length - 1];
|
||||
var firstElement = this.buttonElements[0];
|
||||
|
||||
if (listWidth < this._viewWidth) {
|
||||
// align to horizontal center if list width is smaller than the container
|
||||
return (this._viewWidth - listWidth) / 2 + this._margin;
|
||||
} else if (nodeLeft + nodeWidth >
|
||||
-this._translateX + this._viewWidth + this._margin) {
|
||||
// scroll left if the node falls beyond the right edge of container
|
||||
newTranslate = this._viewWidth - nodeLeft - nodeWidth + this._margin;
|
||||
} else if (nodeLeft < -this._translateX + this._margin) {
|
||||
// scroll right if the node falls beyond the left edge of container
|
||||
newTranslate = -nodeLeft + this._margin;
|
||||
}
|
||||
|
||||
|
||||
// If the new scroll offset contains first/last node, we have to align the
|
||||
// list to begin/end.
|
||||
if (lastElement.offsetLeft + lastElement.offsetWidth <=
|
||||
-newTranslate + this._viewWidth + this._margin) {
|
||||
return this._viewWidth + this._margin - lastElement.offsetLeft -
|
||||
lastElement.offsetWidth;
|
||||
} else if (firstElement.offsetLeft >= -newTranslate + this._margin) {
|
||||
return -firstElement.offsetLeft + this._margin;
|
||||
}
|
||||
return newTranslate;
|
||||
};
|
||||
|
||||
proto._getFocusedElement = function() {
|
||||
return this.buttonElements[this._focusedIndex];
|
||||
};
|
||||
|
||||
proto._focusContent = function() {
|
||||
var elem = this._getFocusedElement();
|
||||
this._scrollTo(elem);
|
||||
|
||||
// move focus to smart dialog while transition running
|
||||
if (elem.focus && (typeof elem.focus) === 'function') {
|
||||
elem.focus();
|
||||
}
|
||||
};
|
||||
|
||||
proto._blurContent = function() {
|
||||
var elem = this._getFocusedElement();
|
||||
if (elem.blur && (typeof elem.blur === 'function')) {
|
||||
elem.blur();
|
||||
}
|
||||
};
|
||||
|
||||
proto.stopKeyNavigation = function() {
|
||||
this.element.removeEventListener('keydown', this);
|
||||
};
|
||||
|
||||
proto.movePrevious = function() {
|
||||
if (this._focusedIndex < 1) {
|
||||
// Do nothing when focus index is at the first button element.
|
||||
return;
|
||||
}
|
||||
|
||||
this._focusedIndex--;
|
||||
this.focus();
|
||||
};
|
||||
|
||||
proto.moveNext = function() {
|
||||
if (this._focusedIndex > this.buttonElements.length - 2) {
|
||||
// Do nothing when focus index is at the last button element
|
||||
return;
|
||||
}
|
||||
this._focusedIndex++;
|
||||
this.focus();
|
||||
};
|
||||
|
||||
proto._handleKeyEvent = function(e) {
|
||||
if (e.keyCode === KeyEvent.DOM_VK_LEFT) {
|
||||
this.movePrevious();
|
||||
} else if (e.keyCode === KeyEvent.DOM_VK_RIGHT) {
|
||||
this.moveNext();
|
||||
}
|
||||
};
|
||||
|
||||
proto.handleEvent = function(e) {
|
||||
this._handleKeyEvent(e);
|
||||
|
||||
switch(e.target) {
|
||||
case this.element:
|
||||
if (e.type === 'will-open' || e.type === 'will-close') {
|
||||
this.fireEvent('modal-dialog-' + e.type);
|
||||
} else if (e.type === 'opened') {
|
||||
this._scrollTo(this.buttonElements[0]);
|
||||
// Play bubble animation when the smart-dialog is opened
|
||||
this.smartBubble.play(this.buttonElements);
|
||||
} else if (e.type === 'closed') {
|
||||
// Do click actions when the smart-dialog is closed
|
||||
this.element.classList.remove('visible');
|
||||
if ((this._clickedIndex || this._clickedIndex === 0) &&
|
||||
this.buttonSettings[this._clickedIndex].onClick) {
|
||||
this.buttonSettings[this._clickedIndex].onClick(
|
||||
this.buttonSettings[this._clickedIndex]);
|
||||
this._clickedIndex = null;
|
||||
} else if (this.onCancel) {
|
||||
// ESC key enter
|
||||
this.onCancel();
|
||||
}
|
||||
this.isOpened = false;
|
||||
this.stopKeyNavigation();
|
||||
this.element.classList.remove('modal-dialog-opened');
|
||||
this.fireEvent('modal-dialog-closed');
|
||||
}
|
||||
break;
|
||||
case this.smartBubble:
|
||||
this.element.classList.add('modal-dialog-opened');
|
||||
this.startKeyNavigation();
|
||||
this.focus();
|
||||
this.fireEvent('modal-dialog-opened');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
SmartModalDialog.prototype = proto;
|
||||
exports.SmartModalDialog = SmartModalDialog;
|
||||
|
||||
})(window);
|
||||
Loading…
Reference in a new issue