mirror of https://github.com/RubaXa/Ply.git
RubaXa
11 years ago
19 changed files with 1588 additions and 1065 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,74 @@
|
||||
// |
||||
// Ply-контекст |
||||
// |
||||
|
||||
|
||||
/** |
||||
* @class Ply.Context |
||||
* @param {HTMLElement} el |
||||
*/ |
||||
function Context(el) { |
||||
/** |
||||
* Корневой элемент |
||||
* @type {HTMLElement} |
||||
*/ |
||||
this.el = el; |
||||
} |
||||
|
||||
Context.fn = Context.prototype = /** @lends Ply.Context */{ |
||||
constructor: Context, |
||||
|
||||
|
||||
/** |
||||
* Получить элемент по имени |
||||
* @param {String} name |
||||
* @returns {HTMLElement|undefined} |
||||
*/ |
||||
getEl: function (name) { |
||||
if (this.el) { |
||||
return _querySelector('[' + _plyAttr + '-name="' + name + '"]', this.el); |
||||
} |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* Получить или установить значение по имени |
||||
* @param {String} name |
||||
* @param {String} [value] |
||||
* @returns {String} |
||||
*/ |
||||
val: function (name, value) { |
||||
var el = typeof name === 'string' ? this.getEl(name) : name; |
||||
|
||||
if (el && (el.value == null)) { |
||||
el = _getElementsByTagName(el, 'input')[0] |
||||
|| _getElementsByTagName(el, 'textarea')[0] |
||||
|| _getElementsByTagName(el, 'select')[0] |
||||
; |
||||
} |
||||
|
||||
if (el && value != null) { |
||||
el.value = value; |
||||
} |
||||
|
||||
return el && el.value || ""; |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* Получить JSON |
||||
* @returns {Object} |
||||
*/ |
||||
toJSON: function () { |
||||
var items = this.el.querySelectorAll('[' + _plyAttr + '-name]'), |
||||
json = {}, |
||||
el, |
||||
i = items.length |
||||
; |
||||
while (i--) { |
||||
el = items[i]; |
||||
json[el.getAttribute(_plyAttr + '-name')] = this.val(el); |
||||
} |
||||
return json; |
||||
} |
||||
}; |
@ -0,0 +1,48 @@
|
||||
/*global support, document*/ |
||||
|
||||
|
||||
/** |
||||
* Хуки для css |
||||
* @type {Object} |
||||
*/ |
||||
var _cssHooks = { |
||||
opacity: !support.opacity && function (style, value) { |
||||
style.zoom = 1; |
||||
style.filter = 'alpha(opacity=' + (value * 100) + ')'; |
||||
} |
||||
}; |
||||
|
||||
|
||||
|
||||
/** |
||||
* Установка или получение css свойства |
||||
* @param {HTMLElement} el |
||||
* @param {Object|String} prop |
||||
* @param {String} [val] |
||||
* @returns {*} |
||||
* @private |
||||
*/ |
||||
function _css(el, prop, val) { |
||||
if (el && el.style && prop) { |
||||
if (prop instanceof Object) { |
||||
for (var name in prop) { |
||||
_css(el, name, prop[name]); |
||||
} |
||||
} |
||||
else if (val === void 0) { |
||||
/* istanbul ignore else */ |
||||
if (document.defaultView && document.defaultView.getComputedStyle) { |
||||
val = document.defaultView.getComputedStyle(el, ''); |
||||
} |
||||
else if (el.currentStyle) { |
||||
val = el.currentStyle; |
||||
} |
||||
|
||||
return prop === void 0 ? val : val[prop]; |
||||
} else if (_cssHooks[prop]) { |
||||
_cssHooks[prop](el.style, val); |
||||
} else { |
||||
el.style[support[prop] || prop] = val; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,28 @@
|
||||
module.exports = { |
||||
zIndex: 10000, |
||||
|
||||
layer: {}, // css |
||||
|
||||
overlay: { |
||||
opacity: .6, |
||||
backgroundColor: 'rgb(0, 0, 0)' |
||||
}, |
||||
|
||||
flags: { |
||||
closeBtn: true, |
||||
bodyScroll: false, |
||||
closeByEsc: true, |
||||
closeByOverlay: true, |
||||
hideLayerInStack: true, |
||||
visibleOverlayInStack: false |
||||
}, |
||||
|
||||
baseHtml: true, |
||||
|
||||
// Callback's |
||||
init: noop, |
||||
open: noop, |
||||
close: noop, |
||||
destroy: noop, |
||||
callback: noop |
||||
}; |
@ -0,0 +1,312 @@
|
||||
// |
||||
// Работа с DOM |
||||
// |
||||
|
||||
|
||||
var $ = require('jquery'); |
||||
|
||||
|
||||
/** |
||||
* Разбор строки "tag#id.foo.bar" |
||||
* @const {RegExp} |
||||
*/ |
||||
var R_SELECTOR = /^(\w+)?(#\w+)?((?:\.[\w_-]+)*)/i; |
||||
|
||||
|
||||
|
||||
/** |
||||
* Выбрать элементы по заданному селектору |
||||
* @param {String} selector |
||||
* @param {HTMLElement} [ctx] |
||||
* @returns {HTMLElement} |
||||
*/ |
||||
function _querySelector(selector, ctx) { |
||||
try { |
||||
return (ctx || document).querySelector(selector); |
||||
} catch (err) { |
||||
/* istanbul ignore next */ |
||||
return $(selector, ctx)[0]; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Найти элементы по имени |
||||
* @param {HTMLElement} el |
||||
* @param {String} name |
||||
* @returns {NodeList} |
||||
*/ |
||||
function _getElementsByTagName(el, name) { |
||||
return el.getElementsByTagName(name); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Присоединить элемент |
||||
* @param {HTMLElement} parent |
||||
* @param {HTMLElement} el |
||||
* @private |
||||
*/ |
||||
function _appendChild(parent, el) { |
||||
try { |
||||
parent && el && parent.appendChild(el); |
||||
} catch (e) {} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Удалить элемент |
||||
* @param {HTMLElement} el |
||||
* @private |
||||
*/ |
||||
function _removeElement(el) { |
||||
/* istanbul ignore else */ |
||||
if (el && el.parentNode) { |
||||
el.parentNode.removeChild(el); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Добавить слуашетеля |
||||
* @param {HTMLElement} el |
||||
* @param {String} name |
||||
* @param {Function} fn |
||||
* @private |
||||
*/ |
||||
function _addEvent(el, name, fn) { |
||||
var handle = fn.handle = fn.handle || ((evt) => { |
||||
/* istanbul ignore if */ |
||||
if (!evt.target) { |
||||
evt.target = evt.srcElement || document; |
||||
} |
||||
|
||||
/* istanbul ignore if */ |
||||
if (evt.target.nodeType === 3) { |
||||
evt.target = evt.target.parentNode; |
||||
} |
||||
|
||||
/* istanbul ignore if */ |
||||
if (!evt.preventDefault) { |
||||
evt.preventDefault = () => { |
||||
evt.returnValue = false; |
||||
}; |
||||
} |
||||
|
||||
/* istanbul ignore if */ |
||||
if (!evt.stopPropagation) { |
||||
evt.stopPropagation = () => { |
||||
evt.cancelBubble = true; |
||||
}; |
||||
} |
||||
|
||||
fn.call(el, evt); |
||||
}); |
||||
|
||||
/* istanbul ignore else */ |
||||
if (el.addEventListener) { |
||||
el.addEventListener(name, handle, false); |
||||
} else { |
||||
el.attachEvent('on' + name, handle); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Удалить слуашетеля |
||||
* @param {HTMLElement} el |
||||
* @param {String} name |
||||
* @param {Function} fn |
||||
* @private |
||||
*/ |
||||
function _removeEvent(el, name, fn) { |
||||
var handle = fn.handle; |
||||
if (handle) { |
||||
/* istanbul ignore else */ |
||||
if (el.removeEventListener) { |
||||
el.removeEventListener(name, handle, false); |
||||
} else { |
||||
el.detachEvent('on' + name, handle); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* Создание DOM структуры по спецификации |
||||
* @param {String|Object|HTMLElement} [spec] |
||||
* @returns {HTMLElement} |
||||
* @private |
||||
*/ |
||||
function _buildDOM(spec) { |
||||
if (spec == null) { |
||||
spec = 'div'; |
||||
} |
||||
|
||||
if (spec.appendChild) { |
||||
return spec; |
||||
} |
||||
else if (spec.skip) { |
||||
return document.createDocumentFragment(); |
||||
} |
||||
|
||||
if (typeof spec === 'string') { // selector |
||||
spec = { tag: spec }; |
||||
} |
||||
|
||||
var el, |
||||
children = spec.children, |
||||
selector = R_SELECTOR.exec(spec.tag || '') |
||||
; |
||||
|
||||
// Это нам больше не нужно |
||||
delete spec.children; |
||||
|
||||
// Разбираем селектор |
||||
spec.tag = selector[1] || 'div'; |
||||
spec.id = spec.id || (selector[2] || '').substr(1); |
||||
|
||||
// Собираем className |
||||
selector = (selector[3] || '').split('.'); |
||||
selector[0] = (spec.className || ''); |
||||
spec.className = selector.join(' '); |
||||
|
||||
// Создаем элемент, теперь можно |
||||
el = document.createElement(spec.tag); |
||||
delete spec.tag; |
||||
|
||||
// Определяем свойсва |
||||
_each(spec, (value, name) => { |
||||
if (value) { |
||||
if (name === 'css') { |
||||
// Определяем CSS свойства |
||||
_css(el, spec.css); |
||||
} |
||||
else if (name === 'text') { |
||||
(value != null) && _appendChild(el, document.createTextNode(value)); |
||||
} |
||||
else if (name === 'html') { |
||||
(value != null) && (el.innerHTML = value); |
||||
} |
||||
else if (name === 'ply') { |
||||
// Ply-аттрибут |
||||
el.setAttribute(_plyAttr, value); |
||||
} |
||||
else if (name in el) { |
||||
try { |
||||
el[name] = value; |
||||
} catch (e) { |
||||
el.setAttribute(name, value); |
||||
} |
||||
} |
||||
else if (/^data-/.test(name)) { |
||||
el.setAttribute(name, value); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
// Детишки |
||||
if (children && children.appendChild) { |
||||
_appendChild(el, children); |
||||
} |
||||
else { |
||||
_each(children, (spec, selector) => { |
||||
if (spec) { |
||||
if (typeof spec === 'string') { |
||||
spec = { text: spec }; |
||||
} |
||||
else if (typeof spec !== 'object') { |
||||
spec = {}; |
||||
} |
||||
|
||||
/* istanbul ignore else */ |
||||
if (typeof selector === 'string') { |
||||
spec.tag = spec.tag || selector; |
||||
} |
||||
|
||||
_appendChild(el, _buildDOM(spec)); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
return el; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Выбрать первый не заполненый элемент |
||||
* @param {HTMLElement} parentNode |
||||
* @private |
||||
*/ |
||||
function _autoFocus(parentNode) { |
||||
var items = _getElementsByTagName(parentNode, 'input'), |
||||
i = 0, |
||||
n = items.length, |
||||
el, |
||||
element |
||||
; |
||||
|
||||
for (; i < n; i++) { |
||||
el = items[i]; |
||||
|
||||
/* istanbul ignore else */ |
||||
if (el.type === 'submit') { |
||||
!element && (element = el); |
||||
} |
||||
else if (!/hidden|check|radio/.test(el.type) && el.value == '') { |
||||
element = el; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!element) { |
||||
element = _getElementsByTagName(parentNode, 'button')[0]; |
||||
} |
||||
|
||||
try { element.focus(); } catch (err) { } |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Предзагрузить все изображения |
||||
* @param {HTMLElement} parentNode |
||||
* @returns {Promise} |
||||
* @private |
||||
*/ |
||||
function _preloadImage(parentNode) { |
||||
_loading(true); |
||||
|
||||
return _promise((resolve) => { |
||||
var items = _getElementsByTagName(parentNode, 'img'), |
||||
i = items.length, |
||||
queue = i, |
||||
img, |
||||
complete = () => { |
||||
/* istanbul ignore else */ |
||||
if (--queue <= 0) { |
||||
i = items.length; |
||||
while (i--) { |
||||
img = items[i]; |
||||
_removeEvent(img, 'load', complete); |
||||
_removeEvent(img, 'error', complete); |
||||
} |
||||
_loading(false); |
||||
resolve(); |
||||
} |
||||
} |
||||
; |
||||
|
||||
while (i--) { |
||||
img = items[i]; |
||||
if (img.complete) { |
||||
queue--; |
||||
} else { |
||||
_addEvent(img, 'load', complete); |
||||
_addEvent(img, 'error', complete); |
||||
} |
||||
} |
||||
|
||||
!queue && complete(); |
||||
}); |
||||
} |
@ -0,0 +1,191 @@
|
||||
module.exports = { |
||||
// Установки по умолчанию |
||||
defaults: { |
||||
duration: 300, |
||||
|
||||
open: { |
||||
layer: null, |
||||
overlay: null |
||||
}, |
||||
|
||||
close: { |
||||
layer: null, |
||||
overlay: null |
||||
} |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* Настройти эффекты по умолчанию |
||||
* @static |
||||
* @param {Object} options |
||||
*/ |
||||
setup: function (options) { |
||||
this.defaults = this.get(options); |
||||
}, |
||||
|
||||
|
||||
set: function (desc) { |
||||
_extend(this, desc); |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* Получить опции на основе переданных и по умолчанию |
||||
* @static |
||||
* @param {Object} options опции |
||||
* @returns {Object} |
||||
*/ |
||||
get: function (options) { |
||||
var defaults = _deepClone(this.defaults); |
||||
|
||||
// Функция разбора выражения `name:duration[args]` |
||||
function parseKey(key) { |
||||
var match = /^([\w_-]+)(?::(\d+%?))?(\[[^\]]+\])?/.exec(key) || []; |
||||
return { |
||||
name: match[1] || key, |
||||
duration: match[2] || null, |
||||
args: JSON.parse(match[3] || 'null') || {} |
||||
}; |
||||
} |
||||
|
||||
|
||||
function toObj(obj, key, def) { |
||||
var fx = parseKey(key), |
||||
val = (obj[fx.name] || def || {}), |
||||
duration = (fx.duration || val.duration || obj.duration || options.duration) |
||||
; |
||||
|
||||
if (typeof val === 'string') { |
||||
val = parseKey(val); |
||||
delete val.args; |
||||
} |
||||
|
||||
if (/%/.test(val.duration)) { |
||||
val.duration = parseInt(val.duration, 10) / 100 * duration; |
||||
} |
||||
|
||||
val.duration = (val.duration || duration) | 0; |
||||
|
||||
return val; |
||||
} |
||||
|
||||
|
||||
if (typeof options === 'string') { |
||||
var fx = parseKey(options); |
||||
options = _deepClone(this[fx.name] || { open: {}, close: {} }); |
||||
options.duration = fx.duration || options.duration; |
||||
options.open.args = fx.args[0]; |
||||
options.close.args = fx.args[1]; |
||||
} |
||||
else if (options instanceof Array) { |
||||
var openFx = parseKey(options[0]), |
||||
closeFx = parseKey(options[1]), |
||||
open = this[openFx.name], |
||||
close = this[closeFx.name] |
||||
; |
||||
|
||||
options = { |
||||
open: _deepClone(open && open.open || { layer: options[0], overlay: options[0] }), |
||||
close: _deepClone(close && close.close || { layer: options[1], overlay: options[1] }) |
||||
}; |
||||
|
||||
options.open.args = openFx.args[0]; |
||||
options.close.args = closeFx.args[0]; |
||||
} |
||||
else if (!(options instanceof Object)) { |
||||
options = {}; |
||||
} |
||||
|
||||
options.duration = (options.duration || defaults.duration) | 0; |
||||
|
||||
for (var key in {open: 0, close: 0}) { |
||||
var val = options[key] || defaults[key] || {}; |
||||
if (typeof val === 'string') { |
||||
// если это строка, то только layer |
||||
val = { layer: val }; |
||||
} |
||||
val.layer = toObj(val, 'layer', defaults[key].layer); |
||||
val.overlay = toObj(val, 'overlay', defaults[key].overlay); |
||||
|
||||
if(val.args === void 0){ |
||||
// clean |
||||
delete val.args; |
||||
} |
||||
|
||||
options[key] = val; |
||||
} |
||||
|
||||
return options; |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* Применить эффекты |
||||
* @static |
||||
* @param {HTMLElement} el элемент, к которому нужно применить эффект |
||||
* @param {String} name название эффекта |
||||
* @returns {Promise|undefined} |
||||
*/ |
||||
apply: function (el, name) { |
||||
name = name.split('.'); |
||||
|
||||
var effects = this[name[0]], // эффекты open/close |
||||
firstEl = el.firstChild, |
||||
oldStyle = [el.getAttribute('style'), firstEl && firstEl.getAttribute('style')], |
||||
fx, |
||||
effect |
||||
; |
||||
|
||||
|
||||
if (support.transition && effects && (effect = effects[name[1]]) && (fx = Ply.effects[effect.name])) { |
||||
if (fx['to'] || fx['from']) { |
||||
// Клонируем |
||||
fx = _deepClone(fx); |
||||
|
||||
// Выключаем анимацию |
||||
_css(el, 'transition', 'none'); |
||||
_css(firstEl, 'transition', 'none'); |
||||
|
||||
// Определяем текущее css-значения |
||||
_each(fx['to'], (val, key, target) => { |
||||
if (val === '&') { |
||||
target[key] = _css(el, key); |
||||
} |
||||
}); |
||||
|
||||
// Выставляем initied значения |
||||
if (isFn(fx['from'])) { |
||||
fx['from'](el, effects.args); |
||||
} else if (fx['from']) { |
||||
_css(el, fx['from']); |
||||
} |
||||
|
||||
return _promise((resolve) => { |
||||
// Принудительный repaint/reflow |
||||
fx.width = el.offsetWidth; |
||||
|
||||
// Включаем анимацию |
||||
_css(el, 'transition', 'all ' + effect.duration + 'ms'); |
||||
_css(firstEl, 'transition', 'all ' + effect.duration + 'ms'); |
||||
|
||||
// Изменяем css |
||||
if (isFn(fx['to'])) { |
||||
fx['to'](el, effects.args); |
||||
} |
||||
else { |
||||
_css(el, fx['to']); |
||||
} |
||||
|
||||
// Ждем завершения анимации |
||||
setTimeout(resolve, effect.duration); |
||||
}).then(() => { |
||||
el.setAttribute('style', oldStyle[0]); |
||||
firstEl && firstEl.setAttribute('style', oldStyle[1]); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
return _resolvePromise(); |
||||
} |
||||
}; |
@ -0,0 +1,137 @@
|
||||
module.exports = { |
||||
// |
||||
// Комбинированный эффекты |
||||
// |
||||
|
||||
'fade': { |
||||
open: { layer: 'fade-in:80%', overlay: 'fade-in:100%' }, |
||||
close: { layer: 'fade-out:60%', overlay: 'fade-out:60%' } |
||||
}, |
||||
|
||||
'scale': { |
||||
open: { layer: 'scale-in', overlay: 'fade-in' }, |
||||
close: { layer: 'scale-out', overlay: 'fade-out' } |
||||
}, |
||||
|
||||
'fall': { |
||||
open: { layer: 'fall-in', overlay: 'fade-in' }, |
||||
close: { layer: 'fall-out', overlay: 'fade-out' } |
||||
}, |
||||
|
||||
'slide': { |
||||
open: { layer: 'slide-in', overlay: 'fade-in' }, |
||||
close: { layer: 'slide-out', overlay: 'fade-out' } |
||||
}, |
||||
|
||||
'3d-flip': { |
||||
open: { layer: '3d-flip-in', overlay: 'fade-in' }, |
||||
close: { layer: '3d-flip-out', overlay: 'fade-out' } |
||||
}, |
||||
|
||||
'3d-sign': { |
||||
open: { layer: '3d-sign-in', overlay: 'fade-in' }, |
||||
close: { layer: '3d-sign-out', overlay: 'fade-out' } |
||||
}, |
||||
|
||||
'inner': { |
||||
open: { layer: 'inner-in' }, |
||||
close: { layer: 'inner-out' } |
||||
}, |
||||
|
||||
|
||||
// |
||||
// Описание эффекта |
||||
// |
||||
|
||||
'fade-in': { |
||||
'from': { opacity: 0 }, |
||||
'to': { opacity: '&' } |
||||
}, |
||||
|
||||
'fade-out': { |
||||
'to': { opacity: 0 } |
||||
}, |
||||
|
||||
'slide-in': { |
||||
'from': { opacity: 0, transform: 'translateY(20%)' }, |
||||
'to': { opacity: '&', transform: 'translateY(0)' } |
||||
}, |
||||
|
||||
'slide-out': { |
||||
'to': { opacity: 0, transform: 'translateY(20%)' } |
||||
}, |
||||
|
||||
'fall-in': { |
||||
'from': { opacity: 0, transform: 'scale(1.3)' }, |
||||
'to': { opacity: '&', transform: 'scale(1)' } |
||||
}, |
||||
|
||||
'fall-out': { |
||||
'to': { opacity: 0, transform: 'scale(1.3)' } |
||||
}, |
||||
|
||||
'scale-in': { |
||||
'from': { opacity: 0, transform: 'scale(0.7)' }, |
||||
'to': { opacity: '&', transform: 'scale(1)' } |
||||
}, |
||||
|
||||
'scale-out': { |
||||
'to': { opacity: 0, 'transform': 'scale(0.7)' } |
||||
}, |
||||
|
||||
'rotate3d': (el, opacity, axis, deg, origin) => { |
||||
_css(el, { perspective: '1300px' }); |
||||
_css(el.firstChild, { |
||||
opacity: opacity, |
||||
transform: 'rotate' + axis + '(' + deg + 'deg)', |
||||
transformStyle: 'preserve-3d', |
||||
transformOrigin: origin ? '50% 0' : '50%' |
||||
}); |
||||
}, |
||||
|
||||
'3d-sign-in': { |
||||
'from': (el) => { |
||||
Ply.effects.rotate3d(el, 0, 'X', -60, '50% 0'); |
||||
}, |
||||
'to': (el) => { |
||||
_css(el.firstChild, { opacity: 1, transform: 'rotateX(0)' }); |
||||
} |
||||
}, |
||||
|
||||
'3d-sign-out': { |
||||
'from': (el) => { |
||||
Ply.effects.rotate3d(el, 1, 'X', 0, '50% 0'); |
||||
}, |
||||
'to': (el) => { |
||||
_css(el.firstChild, { opacity: 0, transform: 'rotateX(-60deg)' }); |
||||
} |
||||
}, |
||||
|
||||
'3d-flip-in': { |
||||
'from': (el, args) => { |
||||
Ply.effects.rotate3d(el, 0, 'Y', args || -70); |
||||
}, |
||||
'to': (el) => { |
||||
_css(el.firstChild, { opacity: 1, transform: 'rotateY(0)' }); |
||||
} |
||||
}, |
||||
|
||||
'3d-flip-out': { |
||||
'from': (el) => { |
||||
Ply.effects.rotate3d(el, 1, 'Y', 0); |
||||
}, |
||||
'to': (el, args) => { |
||||
_css(el.firstChild, { opacity: 0, transform: 'rotateY(' + (args || 70) + 'deg)' }); |
||||
} |
||||
}, |
||||
|
||||
'inner-in': { |
||||
'from': (el) => { _css(el, 'transform', 'translateX(100%)'); }, |
||||
'to': (el) => { _css(el, 'transform', 'translateX(0%)'); } |
||||
}, |
||||
|
||||
'inner-out': { |
||||
'from': (el) => { _css(el, 'transform', 'translateX(0%)'); }, |
||||
'to': (el) => { _css(el, 'transform', 'translateX(-100%)'); } |
||||
} |
||||
}; |
@ -0,0 +1,5 @@
|
||||
module.exports = window.jQuery |
||||
|| /* istanbul ignore next */ window.Zepto |
||||
|| /* istanbul ignore next */ window.ender |
||||
|| /* istanbul ignore next */ window.$ |
||||
; |
@ -0,0 +1,7 @@
|
||||
/** |
||||
* Коды кнопок |
||||
* @type {Object} |
||||
*/ |
||||
module.exports = { |
||||
esc: 27 |
||||
}; |
@ -0,0 +1,5 @@
|
||||
module.exports = { |
||||
ok: 'OK', |
||||
cancel: 'Cancel', |
||||
cross: '✖' |
||||
}; |
@ -0,0 +1,73 @@
|
||||
var array_core = [], |
||||
array_push = array_core.push, |
||||
array_splice = array_core.splice |
||||
; |
||||
|
||||
|
||||
Ply.stack = { |
||||
_idx: {}, |
||||
|
||||
|
||||
/** |
||||
* Последний Ply в стеке |
||||
* @type {Ply} |
||||
*/ |
||||
last: null, |
||||
|
||||
|
||||
/** |
||||
* Длинна стека |
||||
* @type {Number} |
||||
*/ |
||||
length: 0, |
||||
|
||||
|
||||
/** |
||||
* Удаить последний ply-слой из стека |
||||
* @param {Event} evt |
||||
* @private |
||||
*/ |
||||
_pop: function (evt) { |
||||
var layer = Ply.stack.last; |
||||
|
||||
if (evt.keyCode === keys.esc && layer.hasFlag('closeByEsc')) { |
||||
layer.closeBy('esc'); |
||||
} |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* Добавить ply в стек |
||||
* @param {Ply} layer |
||||
*/ |
||||
add: function (layer) { |
||||
var idx = array_push.call(this, layer); |
||||
|
||||
this.last = layer; |
||||
this._idx[layer.cid] = idx - 1; |
||||
|
||||
if (idx === 1) { |
||||
_addEvent(document, 'keyup', this._pop); |
||||
} |
||||
}, |
||||
|
||||
|
||||
/** |
||||
* Удалить ply из стека |
||||
* @param {Ply} layer |
||||
*/ |
||||
remove: function (layer) { |
||||
var idx = this._idx[layer.cid]; |
||||
|
||||
if (idx >= 0) { |
||||
array_splice.call(this, idx, 1); |
||||
|
||||
delete this._idx[layer.cid]; |
||||
this.last = this[this.length-1]; |
||||
|
||||
if (!this.last) { |
||||
_removeEvent(document, 'keyup', this._pop); |
||||
} |
||||
} |
||||
} |
||||
}; |
@ -0,0 +1,25 @@
|
||||
/*global _buildDOM*/ |
||||
module.exports = (() => { |
||||
var props = {}, |
||||
style = document.createElement('div').style, |
||||
names = 'opacity transition transform perspective transformStyle transformOrigin backfaceVisibility'.split(' '), |
||||
prefix = ['Webkit', 'Moz', 'O', 'MS'] |
||||
; |
||||
|
||||
_each(names, (name, i) => { |
||||
props[name] = (name in style) && /* istanbul ignore next */ name; |
||||
|
||||
/* istanbul ignore else */ |
||||
if (!props[name]) { |
||||
for (i = 0; i < 4; i++) { |
||||
var pname = prefix[i] + name.charAt(0).toUpperCase() + name.substr(1); |
||||
/* istanbul ignore else */ |
||||
if (props[name] = (pname in style) && pname) { |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
|
||||
return props; |
||||
})(); |
@ -0,0 +1,133 @@
|
||||
// |
||||
// Вспомогательные методы |
||||
// |
||||
|
||||
var Promise = Deferred || window.Promise; |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* Функция? |
||||
* @param {*} fn |
||||
* @returns {Boolean} |
||||
*/ |
||||
function isFn(fn) { |
||||
return typeof fn === 'function'; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Создать «Обещание» |
||||
* @param {Function} executor |
||||
* @returns {Promise} |
||||
* @private |
||||
*/ |
||||
function _promise(executor) { |
||||
/* istanbul ignore if */ |
||||
if (Promise) { |
||||
return new Promise(executor); |
||||
} else { |
||||
var dfd = $.Deferred(); |
||||
executor(dfd.resolve, dfd.reject); |
||||
return dfd; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Дождаться разрешения всех «Обещаний» |
||||
* @param {Promise[]} iterable |
||||
* @returns {Promise} |
||||
* @private |
||||
*/ |
||||
function _promiseAll(iterable) { |
||||
return Promise |
||||
? /* istanbul ignore next */ Promise.all(iterable) |
||||
: $.when.apply($, iterable); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Вернуть разрешенное «Обещание» |
||||
* @param {*} [value] |
||||
* @returns {Promise} |
||||
* @private |
||||
*/ |
||||
function _resolvePromise(value) { |
||||
return _promise((resolve) => resolve(value)); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Привести значение к «Обещанию» |
||||
* @param {*} value |
||||
* @returns {Promise} |
||||
* @private |
||||
*/ |
||||
function _cast(value) { |
||||
return value && value.then ? value : _resolvePromise(value); |
||||
} |
||||
|
||||
|
||||
|
||||
/** |
||||
* Object iterator |
||||
* @param {Object|Array} obj |
||||
* @param {Function} iterator |
||||
* @private |
||||
*/ |
||||
function _each(obj, iterator) { |
||||
if (obj) { |
||||
for (var key in obj) { |
||||
/* istanbul ignore else */ |
||||
if (obj.hasOwnProperty(key)) { |
||||
iterator(obj[key], key, obj); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Глубокое клонирование |
||||
* @param {*} obj |
||||
* @returns {*} |
||||
* @private |
||||
*/ |
||||
function _deepClone(obj) { |
||||
var result = {}; |
||||
|
||||
_each(obj, (val, key) => { |
||||
if (isFn(val)) { |
||||
result[key] = val; |
||||
} |
||||
else if (val instanceof Object) { |
||||
result[key] = _deepClone(val); |
||||
} |
||||
else { |
||||
result[key] = val; |
||||
} |
||||
}); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Перенос свойств одного объект к другому |
||||
* @param {Object} dst |
||||
* @param {...Object} src |
||||
* @returns {Object} |
||||
* @private |
||||
*/ |
||||
function _extend(dst, ...src) { |
||||
var i = 0, n = src.length; |
||||
for (; i < n; i++) { |
||||
_each(src[i], (val, key) => { |
||||
dst[key] = val; |
||||
}); |
||||
} |
||||
|
||||
return dst; |
||||
} |
Loading…
Reference in new issue