mirror of https://github.com/RubaXa/Ply.git
RubaXa
11 years ago
commit
9d225a0ac8
14 changed files with 3466 additions and 0 deletions
@ -0,0 +1,6 @@
|
||||
temp |
||||
report |
||||
.DS_Store |
||||
node_modules |
||||
Ply.js |
||||
Ply.ui.js |
@ -0,0 +1,66 @@
|
||||
'use strict'; |
||||
|
||||
module.exports = function (grunt){ |
||||
grunt.initConfig({ |
||||
pkg: grunt.file.readJSON('package.json'), |
||||
|
||||
es6transpiler: { |
||||
core: { |
||||
src: 'src/Ply.es6', |
||||
dest: 'Ply.js' |
||||
}, |
||||
ui: { |
||||
src: 'src/Ply.ui.es6', |
||||
dest: 'Ply.ui.js' |
||||
} |
||||
}, |
||||
|
||||
watch: { |
||||
scripts: { |
||||
files: 'src/*.es6', |
||||
tasks: ['es6transpiler'], |
||||
options: { interrupt: true } |
||||
} |
||||
}, |
||||
|
||||
qunit: { |
||||
all: ['tests/*.html'], |
||||
options: { |
||||
'--web-security': 'no', |
||||
coverage: { |
||||
src: ['Ply.js', 'Ply.ui.js'], |
||||
instrumentedFiles: 'temp/', |
||||
htmlReport: 'report/coverage', |
||||
coberturaReport: 'report/', |
||||
linesThresholdPct: 95, |
||||
statementsThresholdPct: 95, |
||||
functionsThresholdPct: 95, |
||||
branchesThresholdPct: 95 |
||||
} |
||||
} |
||||
}, |
||||
|
||||
uglify: { |
||||
options: { |
||||
banner: '/*! <%= pkg.exportName %> <%= pkg.version %> - <%= pkg.license %> | <%= pkg.repository.url %> */\n' |
||||
}, |
||||
dist: { |
||||
files: { |
||||
'<%= pkg.exportName %>.min.js': ['<%= pkg.exportName %>.js'] |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-watch'); |
||||
grunt.loadNpmTasks('grunt-qunit-istanbul'); |
||||
grunt.loadNpmTasks('grunt-es6-transpiler'); |
||||
grunt.loadNpmTasks('grunt-contrib-uglify'); |
||||
|
||||
|
||||
grunt.registerTask('es', ['es6transpiler']); |
||||
grunt.registerTask('build', ['es6transpiler', 'qunit']); |
||||
grunt.registerTask('min', ['build', 'uglify']); |
||||
grunt.registerTask('default', ['build']); |
||||
}; |
After Width: | Height: | Size: 318 B |
@ -0,0 +1,268 @@
|
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>Ply — Amazing layer/modal/dialog system. Wow!</title> |
||||
|
||||
<meta name="keywords" content="ply, layer, modal, dialog, javascript, js, rubaxa"/> |
||||
<meta name="description" content=""/> |
||||
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon"/> |
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon"/> |
||||
|
||||
<link href='http://fonts.googleapis.com/css?family=Lato:300,400' rel='stylesheet' type='text/css'/> |
||||
<link href='./st/app.css' rel='stylesheet' type='text/css'/> |
||||
<link href='./ply.css' rel='stylesheet' type='text/css'/> |
||||
|
||||
</head> |
||||
<body> |
||||
<h1 title="Try demo!"><u>Ply</u></h1> |
||||
|
||||
<div class="container"> |
||||
<div class="row"> |
||||
<h2>Alert</h2> |
||||
|
||||
<div class="col-left"> |
||||
<div class="ply-layer alert example"> |
||||
<div class="ply-content">Hello %username%!</div> |
||||
<div class="ply-footer"><button class="ply-ok">OK</button></div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="col-right"> |
||||
<code> |
||||
Ply.dialog("alert", "Hello %username%!"); |
||||
</code> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="row"> |
||||
<h2>Confirm</h2> |
||||
|
||||
<div class="col-left"> |
||||
<div class="ply-layer confirm example"> |
||||
<div class="ply-content">Continue?</div> |
||||
<div class="ply-footer"><button class="ply-ok">OK</button><button class="ply-cancel">Cancel</button></div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="col-right"> |
||||
<code> |
||||
Ply.dialog( |
||||
"confirm", |
||||
{ effect: "3d-sign" }, |
||||
"Continue?" |
||||
); |
||||
</code> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="row"> |
||||
<h2>Prompt</h2> |
||||
|
||||
<div class="col-left"> |
||||
<div class="ply-layer prompt example"> |
||||
<div class="ply-header">Spam subscribe</div> |
||||
<div class="ply-content"> |
||||
<input class="ply-input" placeholder="E-mail"/> |
||||
</div> |
||||
<div class="ply-footer"><button class="ply-ok">OK</button><button class="ply-cancel">Cancel</button></div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="col-right"> |
||||
<code> |
||||
Ply.dialog("prompt", { |
||||
title: "Spam subscribe", |
||||
form: { email: "E-mail" } |
||||
}); |
||||
</code> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
<div style="height: 100px"></div> |
||||
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> |
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.0/highlight.min.js"></script> |
||||
|
||||
<script src="./Ply.js"></script> |
||||
<script src="./Ply.ui.js"></script> |
||||
|
||||
<script> |
||||
jQuery(function ($) { |
||||
hljs.configure({ classPrefix: '' }); |
||||
|
||||
|
||||
Ply.dialog({ |
||||
foo: { |
||||
data: 'Foo!', |
||||
next: 'bar', |
||||
nextEffect: 'inner' |
||||
}, |
||||
bar: { |
||||
data: { |
||||
text: 'Bar!', |
||||
ok: 'Wow!' |
||||
} |
||||
} |
||||
}); |
||||
|
||||
|
||||
$('.example') |
||||
.each(function () { |
||||
var $el = $(this); |
||||
var $code = $el.closest('.row').find('code'); |
||||
var code = $code.text().split('\n'); |
||||
var offset = code[1].match(/^\s+/)[0].length; |
||||
|
||||
$.each(code, function (i) { |
||||
code[i] = code[i].substr(offset); |
||||
}); |
||||
|
||||
code = code.slice(1).join('\n'); |
||||
$code.text(code); |
||||
$el.data('code', code); |
||||
|
||||
hljs.highlightBlock($code.wrap('<pre/>').parent().addClass('javascript')[0]) |
||||
}) |
||||
.on('click', function () { |
||||
Function($(this).data('code'))(); |
||||
return false; |
||||
}) |
||||
; |
||||
|
||||
|
||||
$('h1 u').click(function () { |
||||
Ply.dialog({ |
||||
'welcome': { |
||||
data: { |
||||
children: [{ |
||||
tag: 'img', |
||||
src: 'http://www.saintjn.org/wp-content/uploads/2013/07/welcome.png?1', |
||||
width: 400 |
||||
}], |
||||
ok: "Next" |
||||
}, |
||||
next: 'introduce', |
||||
nextEffect: '3d-flip[180,-180]' |
||||
}, |
||||
|
||||
'introduce': { |
||||
ui: 'prompt', |
||||
data: { |
||||
title: 'Your name?', |
||||
form: { name: '%username%' } |
||||
}, |
||||
back: 'welcome', |
||||
backEffect: '3d-flip[-180,180]', |
||||
next: 'hi', |
||||
nextEffect: 'scale' |
||||
}, |
||||
|
||||
'hi': { |
||||
data: { |
||||
text: 'Hi, {{name}}!', |
||||
ok: 'Next' |
||||
}, |
||||
prepare: function (data, dialogs) { |
||||
data.text = data.text.replace(/\{\{([^}]+)\}\}/g, function (_, name) { |
||||
return dialogs.introduce.val(name); |
||||
}); |
||||
}, |
||||
back: 'next', |
||||
next: 'question', |
||||
nextEffect: 'fall' |
||||
}, |
||||
|
||||
'question': { |
||||
ui: 'confirm', |
||||
data: { |
||||
text: 'You know Jonna Lee?', |
||||
ok: 'Yes', |
||||
cancel: 'No' |
||||
}, |
||||
back: 'Jonna', |
||||
next: 'Jonna-01', |
||||
nextEffect: '3d-sign' |
||||
}, |
||||
|
||||
'Jonna': { |
||||
data: 'Jonna Lee (born Jonna Emily Lee Nilsson, October 3, 1981) is a singer-songwriter from Linköping, Sweden, currently residing in Stockholm. Lee is best known for being the creator and artist of iamamiwhoami. Lee started her own label "To whom it may concern" in 2010.', |
||||
back: 'next', |
||||
next: 'Jonna-01', |
||||
nextEffect: 'fade' |
||||
}, |
||||
|
||||
'Jonna-01': { |
||||
data: { |
||||
title: 'Jonna Lee', |
||||
children: [{ |
||||
tag: 'img', |
||||
src: 'http://www.movieviral.com/wp-content/uploads/2010/03/jonnalee.jpg', |
||||
width: 400 |
||||
}], |
||||
ok: 'Next' |
||||
}, |
||||
next: 'Jonna-02', |
||||
nextEffect: '3d-flip[180,-180]' |
||||
}, |
||||
|
||||
'Jonna-02': { |
||||
data: { |
||||
title: 'Jonna Lee', |
||||
children: [{ |
||||
tag: 'img', |
||||
src: 'http://2020k.files.wordpress.com/2012/03/iamamiwhoami-good-worker.png', |
||||
width: 400 |
||||
}], |
||||
ok: 'Close', |
||||
cancel: 'Rewind' |
||||
}, |
||||
back: 'welcome' |
||||
} |
||||
}); |
||||
}); |
||||
}); |
||||
</script> |
||||
|
||||
|
||||
<!-- Background --> |
||||
<script> |
||||
(function () { |
||||
function setNoiseBackground(el, color, width, height, opacity) { |
||||
var canvas = document.createElement("canvas"); |
||||
var context = canvas.getContext("2d"); |
||||
|
||||
canvas.width = width; |
||||
canvas.height = height; |
||||
|
||||
for (var i = 0; i < width; i++) { |
||||
for (var j = 0; j < height; j++) { |
||||
var val = Math.floor(Math.random() * 255); |
||||
context.fillStyle = "rgba(" + val + "," + val + "," + val + "," + opacity + ")"; |
||||
context.fillRect(i, j, 1, 1); |
||||
} |
||||
} |
||||
|
||||
el.style.backgroundColor = color; |
||||
el.style.backgroundImage = "url(" + canvas.toDataURL("image/png") + ")"; |
||||
} |
||||
|
||||
// Usage |
||||
setNoiseBackground(document.body, "trasparent", 50, 50, 0.02); |
||||
})(); |
||||
</script> |
||||
|
||||
<script> |
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ |
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), |
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) |
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); |
||||
|
||||
ga('create', 'UA-16483888-3', 'rubaxa.github.io'); |
||||
ga('send', 'pageview'); |
||||
</script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,30 @@
|
||||
{ |
||||
"name": "ply", |
||||
"exportName": "Ply", |
||||
"version": "0.3.0", |
||||
"devDependencies": { |
||||
"grunt": "*", |
||||
"grunt-contrib-watch": "*", |
||||
"grunt-qunit-istanbul": "*", |
||||
"grunt-es6-transpiler": "*", |
||||
"grunt-contrib-uglify": "*" |
||||
}, |
||||
"description": "Ply — Amazing layer/modal/dialog system. Wow!", |
||||
"main": "Ply.js", |
||||
"scripts": { |
||||
"test": "grunt" |
||||
}, |
||||
"repository": { |
||||
"type": "git", |
||||
"url": "git://github.com/rubaxa/Ply.git" |
||||
}, |
||||
"keywords": [ |
||||
"ply", |
||||
"layer", |
||||
"modal", |
||||
"dialog", |
||||
"lightbox" |
||||
], |
||||
"author": "Konstantin Lebedev <ibnRubaXa@gmail.com>", |
||||
"license": "MIT" |
||||
} |
@ -0,0 +1,138 @@
|
||||
/* Loading */ |
||||
.ply-loading { |
||||
top: 50%; |
||||
left: 50%; |
||||
padding: 30px; |
||||
width: 60px; |
||||
height: 60px; |
||||
margin: -100px 0 0 -60px; |
||||
z-index: 100000; |
||||
position: fixed; |
||||
border-radius: 10%; |
||||
background-color: rgba(255,255,255,.5); |
||||
box-shadow: 0 1px 2px rgba(0,0,0,.2); |
||||
} |
||||
|
||||
.ply-loading-spinner { |
||||
width: 100%; |
||||
height: 100%; |
||||
opacity: .9; |
||||
background: #fff; |
||||
border-radius: 100%; |
||||
overflow: hidden; |
||||
position: relative; |
||||
box-shadow: 0 1px 3px rgba(0,0,0,.6); |
||||
} |
||||
|
||||
.ply-loading-spinner::before { |
||||
content: ""; |
||||
display: block; |
||||
width: 100%; |
||||
height: 100%; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
background: #333; |
||||
max-height: 0; |
||||
-webkit-animation: loading 3s normal infinite; |
||||
animation: loading 3s normal infinite; |
||||
} |
||||
|
||||
@keyframes loading { |
||||
0% { max-height: 0; } |
||||
50% { max-height: 100%; top: 0; } |
||||
100% { max-height: 0; top: 120%; } |
||||
} |
||||
|
||||
@-webkit-keyframes loading { |
||||
0% { max-height: 0; } |
||||
50% { max-height: 100%; top: 0; } |
||||
100% { max-height: 0; top: 120%; } |
||||
} |
||||
|
||||
|
||||
/* Layer */ |
||||
.ply-layer { |
||||
color: #333; |
||||
min-width: 280px; |
||||
box-shadow: 0 0 3px rgba(0,0,0,.3); |
||||
background-color: #fff; |
||||
border-radius: 2px; |
||||
font-family: "Arial", Helvetica; |
||||
font-size: 16px; |
||||
} |
||||
.ply-layer.alert .ply-content, |
||||
.ply-layer.confirm .ply-content { |
||||
padding: 40px 30px; |
||||
text-align: center; |
||||
} |
||||
|
||||
.ply-layer.alert .ply-footer, |
||||
.ply-layer.confirm .ply-footer, |
||||
.ply-layer.prompt .ply-footer { |
||||
text-align: center; |
||||
padding-bottom: 20px; |
||||
} |
||||
|
||||
|
||||
.ply-header { |
||||
padding: 10px 20px; |
||||
font-size: 18px; |
||||
background-color: #f1f1f1; |
||||
border-radius: 2px 2px 0 0; |
||||
} |
||||
|
||||
.ply-content { |
||||
padding: 20px; |
||||
} |
||||
|
||||
.ply-footer { |
||||
padding: 0 20px 15px; |
||||
} |
||||
.ply-footer button { |
||||
margin-left: 20px; |
||||
} |
||||
.ply-footer button:first-child { |
||||
margin-left: 0; |
||||
} |
||||
|
||||
|
||||
/* Controls */ |
||||
.ply-ok, |
||||
.ply-cancel { |
||||
color: #fff; |
||||
cursor: pointer; |
||||
border: 0; |
||||
outline: 0; |
||||
padding: 5px 20px; |
||||
box-shadow: 0 1px 1px rgba(0,0,0,.2); |
||||
background-color: #39C082; |
||||
border-radius: 3px; |
||||
font-size: 18px; |
||||
} |
||||
.ply-ok { |
||||
width: 100px; |
||||
} |
||||
|
||||
.ply-cancel { |
||||
background-color: #b2b2b2; |
||||
} |
||||
.ply-ok:focus, |
||||
.ply-cancel:focus { |
||||
box-shadow: 0 0 1px 2px rgba(255, 180, 0, .6); |
||||
} |
||||
|
||||
|
||||
/* Forms */ |
||||
.ply-input { |
||||
width: 100%; |
||||
border: 2px solid #ccc; |
||||
outline: 0; |
||||
padding: 5px 10px; |
||||
font-size: 16px; |
||||
font-family: "Arial", Helvetica; |
||||
box-sizing: border-box; |
||||
} |
||||
.ply-input:focus { |
||||
border-color: #39C082; |
||||
} |
@ -0,0 +1,405 @@
|
||||
/*global define, Ply */ |
||||
((factory) => { |
||||
factory(Ply); |
||||
})((Ply) => { |
||||
'use strict'; |
||||
|
||||
|
||||
var _plyAttr = Ply.attrName, |
||||
noop = Ply.noop, |
||||
_each = Ply.each, |
||||
_extend = Ply.extend, |
||||
_promise = Ply.promise, |
||||
_buildDOM = Ply.dom.build, |
||||
_appendChild = Ply.dom.appendChild, |
||||
_lang = Ply.lang, |
||||
|
||||
_toBlock = (block, name) => { |
||||
if (block == null) { |
||||
return { skip: true }; |
||||
} |
||||
|
||||
if (typeof block === 'string') { |
||||
block = { text: block }; |
||||
} |
||||
|
||||
block.name = block.name || name; |
||||
|
||||
return block; |
||||
} |
||||
; |
||||
|
||||
|
||||
|
||||
/** |
||||
* Управление рендером UI |
||||
* @param {String} name |
||||
* @param {Object} [data] |
||||
* @param {String} [path] |
||||
* @returns {HTMLElement} |
||||
*/ |
||||
function ui(name, data, path) { |
||||
var fn = ui[name], el; |
||||
|
||||
if (!fn) { |
||||
name = name.split(/\s+/).slice(0, -1).join(' '); |
||||
fn = data && ( |
||||
ui[name + ' [name=' + data.name + ']'] |
||||
|| ui[name + ' [type=' + data.type + ']'] |
||||
) |
||||
|| ui[name + ' *'] |
||||
|| ui[':default']; |
||||
} |
||||
|
||||
el = _buildDOM(fn(data, path)); |
||||
if (data && data.name) { |
||||
el.setAttribute(_plyAttr + '-name', data.name); |
||||
} |
||||
el.className += ' ply-ui'; |
||||
|
||||
return el; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Назначение визуализатор |
||||
* @param {String} name имя фабрики |
||||
* @param {Function} renderer |
||||
* @param {Boolean} [simpleMode] |
||||
*/ |
||||
ui.factory = function (name, renderer, simpleMode) { |
||||
ui[name.trim().replace(/\s+/g, ' ')] = function (data, path) { |
||||
var fragment = document.createDocumentFragment(); |
||||
|
||||
if ((data != null) || name === ':root') { |
||||
data = simpleMode ? data : _toBlock(data); |
||||
|
||||
_each(simpleMode ? data : data.children, function (block, key) { |
||||
var abs = ((path || name) + ' ' + key).replace(/^:\w+\s+/, ''); |
||||
var el = ui(abs, _toBlock(block, key), abs); |
||||
|
||||
_appendChild(fragment, el); |
||||
}); |
||||
|
||||
if (!simpleMode) { |
||||
delete data.children; |
||||
} |
||||
|
||||
var result = renderer(data, fragment); |
||||
|
||||
/* istanbul ignore else */ |
||||
if (!result.appendChild) { |
||||
_extend(result, data); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
return fragment; |
||||
}; |
||||
}; |
||||
|
||||
|
||||
// Элемент по умолчанию |
||||
ui.factory(':default', (data, children) => { |
||||
data.children = children; |
||||
return data; |
||||
}); |
||||
|
||||
|
||||
// Ply-слой - корневой элемент |
||||
ui.factory(':root', function (data) { |
||||
return { |
||||
tag: 'form.ply-layer', |
||||
className: data.mod, |
||||
children: [ |
||||
ui(':header', data.header), |
||||
ui(':content', data.content), |
||||
data.ctrls && ui(':default', { |
||||
tag: 'div.ply-footer', |
||||
children: data.ctrls |
||||
}) |
||||
] |
||||
}; |
||||
}); |
||||
|
||||
|
||||
// «Заголовк» слоя |
||||
ui.factory(':header', function (data, children) { |
||||
return { tag: '.ply-header', text: data.text, children: children }; |
||||
}); |
||||
|
||||
|
||||
// «Содержимое» слоя |
||||
ui.factory(':content', function (data, children) { |
||||
return { tag: '.ply-content', children: children }; |
||||
}, true); |
||||
|
||||
|
||||
// Кнопка «ОК» |
||||
ui.factory('ok', function (data) { |
||||
return { |
||||
ply: ':ok', |
||||
tag: 'button.ply-ok', |
||||
text: data === true ? _lang.ok : data |
||||
}; |
||||
}); |
||||
|
||||
|
||||
// Кнопка «Отмена» |
||||
ui.factory('cancel', function (data) { |
||||
return { |
||||
ply: ':close', |
||||
tag: 'button.ply-cancel', |
||||
type: 'reset', |
||||
text: data === true ? _lang.cancel : data |
||||
}; |
||||
}); |
||||
|
||||
|
||||
/** |
||||
* Фабрика слоев |
||||
* @param {String} name |
||||
* @param {Function} renderer |
||||
*/ |
||||
function factory(name, renderer) { |
||||
factory['_' + name] = renderer; |
||||
|
||||
factory[name] = (options, data) => { |
||||
return _promise((resolve, reject) => { |
||||
renderer(options, data, resolve, reject); |
||||
}).then((el) => { |
||||
/* istanbul ignore else */ |
||||
if (!el.appendChild) { |
||||
el = ui(':root', el); |
||||
} |
||||
|
||||
return el; |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Использовать фабрику |
||||
* @param {String} name |
||||
* @param {Object} options |
||||
* @param {Object} data |
||||
* @param {Function} resolve |
||||
* @param {Function} [reject] |
||||
*/ |
||||
factory.use = (name, options, data, resolve, reject) => { |
||||
factory['_' + name](options, data, resolve, reject); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Абстрактный диалог |
||||
* @param {String} mod |
||||
* @param {Object} options |
||||
* @param {Object} data |
||||
* @param {Object} defaults |
||||
* @returns {Object} |
||||
* @private |
||||
*/ |
||||
function _dialogFactory(mod, options, data, defaults) { |
||||
options.effect = options.effect || 'slide'; |
||||
|
||||
return { |
||||
mod: mod, |
||||
header: data.title, |
||||
content: data.form |
||||
? { 'dialog-form': { children: data.form } } |
||||
: { el: data.text || data }, |
||||
ctrls: { |
||||
ok: data.ok || defaults.ok, |
||||
cancel: data.cancel || defaults.cancel |
||||
} |
||||
}; |
||||
} |
||||
|
||||
|
||||
// Фабрика по умолчанию |
||||
factory('default', (options, data, resolve) => { |
||||
resolve(data || /* istanbul ignore next */ {}); |
||||
}); |
||||
|
||||
|
||||
// Диалог: «Предупреждение» |
||||
factory('alert', (options, data, resolve) => { |
||||
resolve(_dialogFactory('alert', options, data, { ok: true })); |
||||
}); |
||||
|
||||
|
||||
// Диалог: «Подтверждение» |
||||
factory('confirm', (options, data, resolve) => { |
||||
resolve(_dialogFactory('confirm', options, data, { |
||||
ok: true, |
||||
cancel: true |
||||
})); |
||||
}); |
||||
|
||||
|
||||
// Диалог: «Запросить данные» |
||||
factory('prompt', (options, data, resolve) => { |
||||
resolve(_dialogFactory('prompt', options, data, { |
||||
ok: true, |
||||
cancel: true |
||||
})); |
||||
}); |
||||
|
||||
|
||||
// Элемент формы |
||||
ui.factory('dialog-form *', (data) => { |
||||
return { |
||||
tag: 'input.ply-input', |
||||
name: data.name, |
||||
value: data.value, |
||||
required: true, |
||||
placeholder: data.hint || data.text |
||||
}; |
||||
}); |
||||
|
||||
|
||||
/** |
||||
* Создать Ply-слой на основе фабрики |
||||
* @param {String} name название фабрики |
||||
* @param {Object} [options] опции |
||||
* @param {Object} [data] данные для фабрики |
||||
* @returns {Promise} |
||||
*/ |
||||
Ply.create = (name, options, data) => { |
||||
if (!data) { |
||||
data = options; |
||||
options = {}; |
||||
} |
||||
|
||||
var renderer = (factory[name] || factory['default']); |
||||
return renderer(options, data).then((el) => { |
||||
return new Ply(_extend(options, { el: el })); |
||||
}); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Открыть Ply-слой |
||||
* @param {String} name |
||||
* @param {Object} [options] |
||||
* @param {Object} [data] |
||||
* @returns {Promise} |
||||
*/ |
||||
Ply.open = (name, options, data) => { |
||||
return Ply.create(name, options, data).then((layer) => { |
||||
return layer.open(); |
||||
}); |
||||
}; |
||||
|
||||
|
||||
/** |
||||
* Создать диалог или систему диалогов |
||||
* @param {String|Object} name |
||||
* @param {Object} [options] |
||||
* @param {Object} [data] |
||||
* @returns {Promise} |
||||
*/ |
||||
Ply.dialog = (name, options, data) => { |
||||
if (name instanceof Object) { |
||||
options = options || /* istanbul ignore next */ {}; |
||||
|
||||
return _promise((resolve, reject) => { |
||||
var first = options.initState, |
||||
current, |
||||
rootLayer, |
||||
stack = name, |
||||
dialogs = {}, |
||||
|
||||
_progress = (ui, layer) => { |
||||
(options.progress || /* istanbul ignore next */ noop)(_extend({ |
||||
name: current.$name, |
||||
index: current.$index, |
||||
length: length, |
||||
stack: stack, |
||||
current: current, |
||||
layer: layer |
||||
}, ui), dialogs); |
||||
}, |
||||
|
||||
changeLayer = (spec, effect, callback) => { |
||||
// Клонирование данных |
||||
var data = JSON.parse(JSON.stringify(spec.data)); |
||||
|
||||
current = spec; |
||||
(spec.prepare || noop)(data, dialogs); |
||||
|
||||
Ply.create(spec.ui || 'alert', spec.options || {}, data).then((layer) => { |
||||
var promise; |
||||
|
||||
if (rootLayer) { |
||||
promise = rootLayer.swap(layer, effect); |
||||
} else { |
||||
promise = layer.open(); |
||||
rootLayer = layer; |
||||
} |
||||
|
||||
promise.then(() => { |
||||
dialogs[spec.$name].el = rootLayer.layerEl; |
||||
}); |
||||
|
||||
callback(layer); |
||||
}); |
||||
} |
||||
; |
||||
|
||||
|
||||
var length = 0; |
||||
_each(stack, (spec, key) => { |
||||
first = first || key; |
||||
spec.effects = spec.effects || {}; |
||||
spec.$name = key; |
||||
spec.$index = length++; |
||||
dialogs[key] = new Ply.Context(); |
||||
}); |
||||
stack.$length = length; |
||||
|
||||
|
||||
changeLayer(stack[first], null, (layer) => { |
||||
_progress({}, layer); |
||||
|
||||
//noinspection FunctionWithInconsistentReturnsJS |
||||
rootLayer.options.callback = (ui) => { |
||||
var isNext = ui.state || (current.back === 'next'), |
||||
swap = isNext ? stack[current.next] : stack[current.back] |
||||
; |
||||
|
||||
if (swap) { |
||||
changeLayer(swap, current[isNext ? 'nextEffect' : 'backEffect'], (layer) => { |
||||
_progress(ui, layer); |
||||
}); |
||||
|
||||
return false; |
||||
} else { |
||||
(ui.state ? resolve : /* istanbul ignore next */ reject)(ui, dialogs); |
||||
} |
||||
}; |
||||
}); |
||||
}); |
||||
} |
||||
else { |
||||
if (!data) { |
||||
data = options || {}; |
||||
options = {}; |
||||
} |
||||
|
||||
return Ply.open(name, options, data).then((layer) => { |
||||
return _promise((resolve) => { |
||||
layer.options.callback = resolve; |
||||
}); |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
|
||||
// Export |
||||
Ply.ui = ui; |
||||
Ply.factory = factory; |
||||
}); |
@ -0,0 +1,149 @@
|
||||
html { |
||||
background-color: #ac0; |
||||
} |
||||
|
||||
html, body { |
||||
height: 100%; |
||||
} |
||||
|
||||
.container { |
||||
margin: 0 auto; |
||||
width: 80%; |
||||
min-width: 600px; |
||||
max-width: 1200px; |
||||
} |
||||
|
||||
body, h1, h2 { |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
h1, h2 { |
||||
color: #fff; |
||||
font-family: 'Lato', sans-serif; |
||||
font-weight: 300; |
||||
text-shadow: 0 1px 1px rgba(0,0,0,.2); |
||||
} |
||||
|
||||
|
||||
h1 { |
||||
text-shadow: 0 1px 3px rgba(0,0,0,.2); |
||||
font-size: 200px; |
||||
text-align: center; |
||||
margin-top: 50px; |
||||
margin-bottom: 50px; |
||||
} |
||||
h1 u { |
||||
cursor: pointer; |
||||
border-bottom: 8px dotted #fff; |
||||
text-decoration: none; |
||||
} |
||||
|
||||
h2 { |
||||
font-size: 30px; |
||||
margin-bottom: 10px; |
||||
} |
||||
|
||||
|
||||
.row { |
||||
margin-bottom: 30px; |
||||
} |
||||
.row:after { |
||||
clear: both; |
||||
content: ''; |
||||
display: block; |
||||
} |
||||
|
||||
.col-left { |
||||
float: left; |
||||
width: 35%; |
||||
padding: 0 20px; |
||||
box-sizing: content-box; |
||||
} |
||||
|
||||
.col-right { |
||||
float: left; |
||||
width: 55%; |
||||
margin-left: 5%; |
||||
} |
||||
|
||||
.example { |
||||
cursor: pointer; |
||||
opacity: 0.95; |
||||
position: relative; |
||||
} |
||||
.example:hover:after { |
||||
top: 50%; |
||||
left: 50%; |
||||
line-height: 0; |
||||
margin: -5px 0 0 -50px; |
||||
color: #333; |
||||
content: '►'; |
||||
font-size: 100px; |
||||
position: absolute; |
||||
display: block; |
||||
opacity: .7; |
||||
} |
||||
|
||||
.example:hover { |
||||
opacity: 1; |
||||
} |
||||
|
||||
pre code { |
||||
background-color: #fff; |
||||
box-shadow: 0 1px 1px rgba(0,0,0,.3); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
/* Tomorrow Theme */ |
||||
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ |
||||
/* Original theme - https://github.com/chriskempson/tomorrow-theme */ |
||||
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ |
||||
.tomorrow-comment, pre .comment, pre .title { |
||||
color: #8e908c; |
||||
} |
||||
|
||||
.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { |
||||
color: #c82829; |
||||
} |
||||
|
||||
.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { |
||||
color: #f5871f; |
||||
} |
||||
|
||||
.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { |
||||
color: #eab700; |
||||
} |
||||
|
||||
.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { |
||||
color: #718c00; |
||||
} |
||||
|
||||
.tomorrow-aqua, pre .css .hexcolor { |
||||
color: #3e999f; |
||||
} |
||||
|
||||
.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { |
||||
color: #4271ae; |
||||
} |
||||
|
||||
.tomorrow-purple, pre .keyword, pre .javascript .function { |
||||
color: #8959a8; |
||||
} |
||||
|
||||
pre { |
||||
border: 0; |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
|
||||
pre code { |
||||
display: block; |
||||
color: #4d4d4c; |
||||
font-size: 15px; |
||||
font-family: Menlo, Monaco, Consolas, monospace; |
||||
line-height: 1.5; |
||||
padding: 30px; |
||||
} |
@ -0,0 +1,115 @@
|
||||
(function (Ply) { |
||||
module('Ply.dom'); |
||||
|
||||
|
||||
function elementEqual(actual, expected, msg) { |
||||
msg = msg || 'el'; |
||||
expected.tagName = (expected.tagName || 'div').toUpperCase(); |
||||
|
||||
Ply.each(expected, function (value, attr) { |
||||
equal(actual[attr] || actual.getAttribute(attr), value, msg + '.' + attr); |
||||
}); |
||||
} |
||||
|
||||
|
||||
test('build()', function () { |
||||
elementEqual(Ply.dom.build(), { }); |
||||
}); |
||||
|
||||
|
||||
test('build("string")', function () { |
||||
Ply.each({ |
||||
'div': { }, |
||||
'div#xxx': { id: 'xxx' }, |
||||
'div.foo': { className: ' foo' }, |
||||
'div#xxx.foo': { id: 'xxx', className: ' foo' }, |
||||
'b.foo.bar': { tagName: 'B', className: ' foo bar' }, |
||||
'span#xxx.foo.bar': { tagName: 'SPAN', id: 'xxx', className: ' foo bar' }, |
||||
'#xxx': { id: 'xxx' }, |
||||
'#xxx.foo': { id: 'xxx', className: ' foo' }, |
||||
'#xxx.foo.bar': { id: 'xxx', className: ' foo bar' } |
||||
}, function (data, selector) { |
||||
elementEqual(Ply.dom.build(selector), data, selector); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
test('build({ })', function () { |
||||
elementEqual(Ply.dom.build({ |
||||
id: 'baz', |
||||
tag: 'input.foo', |
||||
className: 'bar', |
||||
ply: 'baz', |
||||
'data-prop': 'qux' |
||||
}), { |
||||
id: 'baz', |
||||
tagName: 'INPUT', |
||||
className: 'bar foo', |
||||
'data-ply': 'baz', |
||||
'data-prop': 'qux' |
||||
}, '{}'); |
||||
|
||||
elementEqual(Ply.dom.build({ text: '<b>foo</b>' }), { innerHTML: '<b>foo</b>' }, 'text'); |
||||
elementEqual(Ply.dom.build({ html: '<b>bar</b>' }), { innerHTML: '<b>bar</b>' }, 'html'); |
||||
}); |
||||
|
||||
|
||||
test('build(element)', function () { |
||||
var el = Ply.dom.build(Ply.dom.build('b.foo')); |
||||
elementEqual(el, { tagName: 'b', className: ' foo' }); |
||||
}); |
||||
|
||||
|
||||
test('build({ children: {} })', function () { |
||||
var el = Ply.dom.build({ |
||||
tag: 'form', |
||||
children: { |
||||
'input': { |
||||
type: 'password' |
||||
}, |
||||
'hr': true, |
||||
'br': false, |
||||
'button': 'Enter' |
||||
} |
||||
}); |
||||
|
||||
equal(el.childNodes.length, 3); |
||||
|
||||
elementEqual(el, { tagName: 'form' }); |
||||
elementEqual(el.childNodes[0], { tagName: 'input', type: 'password' }); |
||||
elementEqual(el.childNodes[1], { tagName: 'hr' }); |
||||
elementEqual(el.childNodes[2], { tagName: 'button', innerHTML: 'Enter' }); |
||||
}); |
||||
|
||||
|
||||
test('build({ children: [] })', function () { |
||||
var el = Ply.dom.build({ |
||||
tag: 'form', |
||||
children: [ |
||||
{ |
||||
tag: 'input', |
||||
type: 'checkbox', |
||||
disabled: true |
||||
}, |
||||
{ tag: 'hr', skip: true }, |
||||
false && { tag: bar }, |
||||
{ tag: 'button', text: "Enter" } |
||||
] |
||||
}); |
||||
|
||||
equal(el.childNodes.length, 2); |
||||
|
||||
elementEqual(el, { tagName: 'form' }); |
||||
elementEqual(el.childNodes[0], { tagName: 'input', type: 'checkbox', disabled: true }); |
||||
elementEqual(el.childNodes[1], { tagName: 'button', innerHTML: 'Enter' }); |
||||
}); |
||||
|
||||
|
||||
test('build({ children: el })', function () { |
||||
var el = Ply.dom.build({ |
||||
children: Ply.dom.build({ tag: 'b', text: '!' }) |
||||
}); |
||||
|
||||
elementEqual(el, { innerHTML: '<b>!</b>' }); |
||||
}); |
||||
})(Ply); |
@ -0,0 +1,237 @@
|
||||
(function (Ply) { |
||||
module('Ply.effects'); |
||||
|
||||
|
||||
test('core', function () { |
||||
Ply.effects.defaults = { duration: 300, open: {}, close: {} }; |
||||
|
||||
|
||||
deepEqual(Ply.effects.get(), { |
||||
open: { |
||||
layer: { duration: 300 }, |
||||
overlay: { duration: 300 } |
||||
}, |
||||
close: { |
||||
layer: { duration: 300 }, |
||||
overlay: { duration: 300 } |
||||
}, |
||||
duration: 300 |
||||
}, 'def'); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get(['fade-in', 'fade-out']), { |
||||
open: { |
||||
layer: { name: 'fade-in', duration: 300 }, |
||||
overlay: { name: 'fade-in', duration: 300 } |
||||
}, |
||||
close: { |
||||
layer: { name: 'fade-out', duration: 300 }, |
||||
overlay: { name: 'fade-out', duration: 300 } |
||||
}, |
||||
duration: 300 |
||||
}, "['fade-in', 'fade-out']"); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get(['fade-in', 'fade-out:100']), { |
||||
open: { |
||||
layer: { name: 'fade-in', duration: 300 }, |
||||
overlay: { name: 'fade-in', duration: 300 } |
||||
}, |
||||
close: { |
||||
layer: { name: 'fade-out', duration: 100 }, |
||||
overlay: { name: 'fade-out', duration: 100 } |
||||
}, |
||||
duration: 300 |
||||
}, "['fade-in', 'fade-out:100']"); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get('fade:100'), { |
||||
open: { |
||||
layer: { name: 'fade-in', duration: 100 * 0.8 }, |
||||
overlay: { name: 'fade-in', duration: 100 } |
||||
}, |
||||
close: { |
||||
layer: { name: 'fade-out', duration: 100 * 0.6 }, |
||||
overlay: { name: 'fade-out', duration: 100 * 0.6 } |
||||
}, |
||||
duration: 100 |
||||
}, 'fade:100'); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get({ |
||||
open: 'slide-in', |
||||
close: 'slide-out' |
||||
}), { |
||||
open: { |
||||
layer: { name: 'slide-in', duration: 300 }, |
||||
overlay: { duration: 300 } |
||||
}, |
||||
close: { |
||||
layer: { name: 'slide-out', duration: 300 }, |
||||
overlay: { duration: 300 } |
||||
}, |
||||
duration: 300 |
||||
}, 'slide-in-out'); |
||||
|
||||
|
||||
|
||||
Ply.effects.setup({ open: 'fade-in' }); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get(), { |
||||
open: { |
||||
layer: { name: 'fade-in', duration: 300 }, |
||||
overlay: { duration: 300 } |
||||
}, |
||||
close: { |
||||
layer: { duration: 300 }, |
||||
overlay: { duration: 300 } |
||||
}, |
||||
duration: 300 |
||||
}, 'open.fade-in'); |
||||
|
||||
|
||||
Ply.effects.setup({ open: { overlay: 'fade-in' } }); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get({ |
||||
open: 'slide-in', |
||||
close: 'slide-out' |
||||
}), { |
||||
open: { |
||||
layer: { name: 'slide-in', duration: 300 }, |
||||
overlay: { name: 'fade-in', duration: 300 } |
||||
}, |
||||
close: { |
||||
layer: { name: 'slide-out', duration: 300 }, |
||||
overlay: { duration: 300 } |
||||
}, |
||||
duration: 300 |
||||
}); |
||||
|
||||
|
||||
Ply.effects.setup('fade:400'); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get({ |
||||
open: 'slide-in', |
||||
close: 'slide-out' |
||||
}), { |
||||
open: { |
||||
layer: { name: 'slide-in', duration: 400 }, |
||||
overlay: { name: 'fade-in', duration: 400 } |
||||
}, |
||||
close: { |
||||
layer: { name: 'slide-out', duration: 400 }, |
||||
overlay: { name: 'fade-out', duration: 400 * 0.6 } |
||||
}, |
||||
duration: 400 |
||||
}, 'fade:400'); |
||||
}); |
||||
|
||||
|
||||
test('effects:args', function () { |
||||
Ply.effects.defaults = { duration: 300, open: {}, close: {} }; |
||||
|
||||
deepEqual(Ply.effects.get('scale[0.5,0.3]'), { |
||||
open: { |
||||
args: 0.5, |
||||
layer: { name: 'scale-in', duration: 300 }, |
||||
overlay: { name: 'fade-in', duration: 300 } |
||||
}, |
||||
close: { |
||||
args: 0.3, |
||||
layer: { name: 'scale-out', duration: 300 }, |
||||
overlay: { name: 'fade-out', duration: 300 } |
||||
}, |
||||
duration: 300 |
||||
}); |
||||
|
||||
|
||||
deepEqual(Ply.effects.get(['scale["foo"]', 'fall[{"bar":"baz"}]']), { |
||||
open: { |
||||
args: 'foo', |
||||
layer: { name: 'scale-in', duration: 300 }, |
||||
overlay: { name: 'fade-in', duration: 300 } |
||||
}, |
||||
close: { |
||||
args: {bar:'baz'}, |
||||
layer: { name: 'fall-out', duration: 300 }, |
||||
overlay: { name: 'fade-out', duration: 300 } |
||||
}, |
||||
duration: 300 |
||||
}); |
||||
}); |
||||
|
||||
|
||||
test('stress', function () { |
||||
try { |
||||
Ply.effects.get(null); |
||||
Ply.effects.get(void 0); |
||||
Ply.effects.get(Math.random()); |
||||
Ply.effects.get('---'); |
||||
Ply.effects.get(123); |
||||
Ply.effects.get('\n'); |
||||
Ply.effects.get([null, null]); |
||||
Ply.effects.get([void 0, void 0]); |
||||
Ply.effects.get(['\n', '\t']); |
||||
ok(true); |
||||
} catch (err) { |
||||
equal([err, err.stack], null); |
||||
} |
||||
}); |
||||
|
||||
|
||||
promiseTest('fade', function () { |
||||
var log = { open: [], close: [] }, |
||||
type = 'open', |
||||
pid, i, |
||||
layer = new Ply({ effect: 'fade' }) |
||||
; |
||||
|
||||
pid = setInterval(function () { |
||||
log[type].push( parseFloat(Ply.css(layer.overlayEl, 'opacity')) ); |
||||
}, 50); |
||||
|
||||
return layer.open().then(function () { |
||||
type = 'close'; |
||||
return layer.close(); |
||||
}).then(function () { |
||||
ok(log.open.length > 2, 'open'); |
||||
ok(log.close.length > 2, 'close'); |
||||
|
||||
for (i = 1; i < log.open.length; i++) { |
||||
if (log.open[i] < log.open[i-1]) { |
||||
equal(log.open, null, 'open: ' + i); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
for (i = 1; i < log.close.length; i++) { |
||||
if (log.close[i] > log.close[i-1]) { |
||||
equal(log.close, null, 'close: ' + i); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
clearInterval(pid); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('other', function () { |
||||
expect(0); |
||||
|
||||
var queue = Ply.promise(function (resolve) { resolve() }); |
||||
|
||||
Ply.each('scale fall slide 3d-flip 3d-sign'.split(' '), function (name) { |
||||
queue = queue.then(function () { |
||||
return new Ply({ effect: name + ':50' }).open().then(function (layer) { |
||||
return layer.close(); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
return queue; |
||||
}); |
||||
})(Ply); |
@ -0,0 +1,250 @@
|
||||
(function () { |
||||
module('Ply'); |
||||
|
||||
var layer; |
||||
|
||||
test('core', function () { |
||||
equal(typeof Ply, 'function'); |
||||
ok(new Ply instanceof Ply); |
||||
}); |
||||
|
||||
|
||||
function sleep(fn, ms) { |
||||
return Ply.promise(function (resolve) { |
||||
setTimeout(function () { |
||||
fn(); |
||||
resolve(); |
||||
}, ms); |
||||
}); |
||||
} |
||||
|
||||
|
||||
function checkVisiblity(layer, state, msg) { |
||||
equal(!!layer.visible, state, '[' + msg + '] visible: ' + state); |
||||
equal(!!layer.wrapEl.parentNode, state, msg + ' -> parentNode is ' + (state ? '' : 'not') + 'exists'); |
||||
} |
||||
|
||||
|
||||
test('options', function () { |
||||
layer = new Ply(); |
||||
|
||||
for (var key in Ply.defaults.overlay) { |
||||
equal(layer.overlayEl.style[key], Ply.defaults.overlay[key], key); |
||||
} |
||||
equal(layer.bodyEl, document.body, 'body'); |
||||
|
||||
// Body
|
||||
layer = new Ply({ body: '#playground' }); |
||||
equal(layer.bodyEl, playground, '#playground'); |
||||
|
||||
// Overlay 1
|
||||
layer = new Ply({ overlay: { opacity: 1 } }); |
||||
equal(layer.overlayEl.style.opacity, 1, 'opacity: 1'); |
||||
equal(layer.overlayEl.style.backgroundColor, "", 'backgroundColor: ""'); |
||||
|
||||
// Overlay 2
|
||||
layer = new Ply({ overlay: { opacity: 1, backgroundColor: 'rgb(255, 0, 0)' } }); |
||||
equal(layer.overlayEl.style.opacity, 1, 'opacity: 1'); |
||||
equal(layer.overlayEl.style.backgroundColor, 'rgb(255, 0, 0)', 'backgroundColor: red'); |
||||
|
||||
// Overlay 3
|
||||
layer = new Ply({ overlay: null }); |
||||
notEqual(layer.overlayEl.style.position, 'fixed', 'overlay: null'); |
||||
|
||||
// Layer
|
||||
layer = new Ply({ layer: { textAlign: 'center' } }); |
||||
equal(layer.contentEl.style.textAlign, 'center', 'textAlign: center'); |
||||
}); |
||||
|
||||
|
||||
test('flags', function () { |
||||
layer = new Ply(); |
||||
for (var key in Ply.defaults.flags) { |
||||
equal(layer.options.flags[key], Ply.defaults.flags[key], key); |
||||
} |
||||
|
||||
|
||||
layer = new Ply({ flags: { bodyScroll: true } }); |
||||
for (var key in Ply.defaults.flags) { |
||||
equal(layer.options.flags[key], key == 'bodyScroll' ? true : Ply.defaults.flags[key], key); |
||||
} |
||||
}); |
||||
|
||||
|
||||
test('content', function () { |
||||
var content = document.createElement('b'); |
||||
content.innerHTML = '!'; |
||||
|
||||
equal(new Ply().contentEl.innerHTML, ''); |
||||
equal(new Ply({ el: 'Wow!' }).contentEl.innerHTML, 'Wow!'); |
||||
equal(new Ply({ el: content }).layerEl.innerHTML, '<b>!</b>'); |
||||
}); |
||||
|
||||
|
||||
promiseTest('open/close', function () { |
||||
layer = new Ply({ el: 'Wow!' }); |
||||
|
||||
ok(!layer.wrapEl.parentNode, '!parent - open'); |
||||
ok(!layer.visible, 'visible: false'); |
||||
|
||||
return layer.open().then(function () { |
||||
var ratio = layer.wrapEl.offsetHeight / (layer.layerEl.offsetTop + layer.layerEl.offsetHeight/2); |
||||
|
||||
ok(layer.visible, 'visible: true'); |
||||
ok(layer.wrapEl.offsetWidth > 0, 'offsetWidth > 0'); |
||||
ok(Math.abs(2 - ratio) < 0.1, ratio, 'delat(' + ratio + ') < 0.1'); |
||||
|
||||
layer.close().then(function () { |
||||
ok(!layer.visible, 'visible: false - close'); |
||||
ok(!layer.wrapEl.parentNode, '!parent - close'); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('closeByEsc', function () { |
||||
function open(msg, esc) { |
||||
var layer = new Ply({ flags: { closeByEsc: esc }, effect: { duration: 1 } }); |
||||
|
||||
checkVisiblity(layer, false, msg); |
||||
|
||||
return layer.open().then(function () { |
||||
checkVisiblity(layer, true, msg); |
||||
return layer; |
||||
}); |
||||
} |
||||
|
||||
|
||||
return open('1. esc: true', true).then(function (escTrue) { |
||||
return open('2. esc: false', false).then(function (escFalse) { |
||||
simulateEvent(document, 'keyup', { keyCode: Ply.keys.esc }); |
||||
|
||||
checkVisiblity(escTrue, true, '3. esc: true'); |
||||
checkVisiblity(escFalse, true, '4. esc: false'); |
||||
|
||||
return escFalse.close().then(function () { |
||||
checkVisiblity(escTrue, true, '5. esc: true'); |
||||
checkVisiblity(escFalse, false, '6. esc: false'); |
||||
|
||||
simulateEvent(document, 'keyup', { keyCode: Ply.keys.esc }); |
||||
|
||||
return sleep(function () { |
||||
checkVisiblity(escTrue, false, '7. esc: true'); |
||||
checkVisiblity(escFalse, false, '8. esc: false'); |
||||
}, 50); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('closeByOverlay', function () { |
||||
function test(msg, state, callback) { |
||||
var layer = new Ply({ flags: { closeByOverlay: state }, effect: { duration: 1 } }); |
||||
return layer.open().then(function () { |
||||
checkVisiblity(layer, true, msg); |
||||
simulateEvent(layer.overlayEl, 'click'); |
||||
|
||||
return sleep(function () { |
||||
callback(layer, msg); |
||||
}, 50); |
||||
}); |
||||
} |
||||
|
||||
|
||||
return test('closeByOverlay: true', true, function (layer, msg) { |
||||
checkVisiblity(layer, false, msg); |
||||
|
||||
return test('closeByOverlay: false', false, function (layer, msg) { |
||||
checkVisiblity(layer, true, msg); |
||||
return layer.close(); |
||||
}); |
||||
}) |
||||
}); |
||||
|
||||
|
||||
promiseTest('swap', function () { |
||||
return new Ply({ el: 1, effect: 'none:1' }).open().then(function (layer) { |
||||
return layer.swap({ el: 2 }).then(function () { |
||||
equal(layer.contentEl.innerHTML, 2); |
||||
|
||||
return layer.close().then(function () { |
||||
return layer.swap({ el: 3 }, 'none:2').then(function () { |
||||
equal(layer.contentEl.innerHTML, 3); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('destory', function () { |
||||
return new Ply({ effect: 'none:1' }).open().then(function (layer) { |
||||
checkVisiblity(layer, true, '#1'); |
||||
|
||||
layer.destroy(); |
||||
|
||||
checkVisiblity(layer, false, '#2'); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('on/off', function () { |
||||
var log = [], |
||||
logMe = function (prefix, evt, el) { |
||||
log.push(prefix + ':' + el.tagName + '.' + evt.type + '->' + el.getAttribute('data-ply')); |
||||
}, |
||||
barHandle = function (evt, el) { |
||||
log.pop(); |
||||
logMe('bar', evt, el); |
||||
} |
||||
; |
||||
|
||||
return new Ply({ el: '<i data-ply="foo"><em>foo</em></i><b data-ply="bar"><em>bar</em></b>' }).open().then(function (layer) { |
||||
layer.on('click', function (evt, el) { |
||||
logMe('layer', evt, el); |
||||
}); |
||||
|
||||
layer.on('click', 'foo', function (evt, el) { |
||||
logMe('foo', evt, el); |
||||
}); |
||||
|
||||
layer.on('click', 'bar', barHandle); |
||||
|
||||
simulateEvent(layer.contentEl.getElementsByTagName('em')[0], 'click'); |
||||
simulateEvent(layer.contentEl.getElementsByTagName('em')[1], 'click'); |
||||
|
||||
layer.off('click', barHandle); |
||||
|
||||
simulateEvent(layer.contentEl.getElementsByTagName('em')[1], 'click'); |
||||
|
||||
layer.off('click', 'bar', barHandle); |
||||
|
||||
simulateEvent(layer.contentEl.getElementsByTagName('em')[1], 'click'); |
||||
|
||||
equal(log.join('\n'), [ |
||||
'layer:DIV.click->layer', |
||||
'foo:I.click->foo', |
||||
'bar:B.click->bar', |
||||
'bar:B.click->bar', |
||||
'layer:DIV.click->layer' |
||||
].join('\n')); |
||||
|
||||
return layer.close(); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
// if (/state=2/.test(location)) {
|
||||
// promiseTest('Promise', function () {
|
||||
// expect(0);
|
||||
//
|
||||
// return Ply.promise(function (resolve) {
|
||||
// window.resolveTest = function () {
|
||||
// resolve();
|
||||
// };
|
||||
// document.write('<iframe src="?state=2"></iframe>');
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
})(); |
@ -0,0 +1,131 @@
|
||||
(function (Ply) { |
||||
module('Ply.ui'); |
||||
|
||||
|
||||
promiseTest('dialog("unknown")', function () { |
||||
setTimeout(function () { |
||||
simulateEvent(Ply.stack.last.overlayEl, 'click'); |
||||
}, 50); |
||||
|
||||
return Ply.dialog('unknown').then(function (ui) { |
||||
equal(ui.by, 'overlay', 'ui.by'); |
||||
equal(ui.state, false, 'ui.state'); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('dialog("alert")', function () { |
||||
setTimeout(function () { |
||||
var el = Ply.stack.last.wrapEl; |
||||
simulateEvent(el.getElementsByTagName('button')[0], 'click'); |
||||
}, 50); |
||||
|
||||
return Ply.dialog('alert', { effect: 'none:1' }, 'msg').then(function (ui) { |
||||
equal(ui.by, 'submit', 'ui.by'); |
||||
equal(ui.state, true, 'ui.state'); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('dialog("confirm")', function () { |
||||
setTimeout(function () { |
||||
var el = Ply.stack.last.wrapEl; |
||||
simulateEvent(el.getElementsByTagName('button')[1], 'click'); |
||||
}, 50); |
||||
|
||||
return Ply.dialog('confirm', { effect: 'none:1' }, { |
||||
title: "???", |
||||
text: "!!!" |
||||
}).then(function (ui) { |
||||
equal(ui.by, 'cancel', 'ui.by'); |
||||
equal(ui.state, false, 'ui.state'); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('dialog("prompt")', function () { |
||||
setTimeout(function () { |
||||
var el = Ply.stack.last.wrapEl; |
||||
Ply.stack.last.context.val('email', 'xx@yy.zz'); |
||||
simulateEvent(el.getElementsByTagName('button')[0], 'click'); |
||||
}, 50); |
||||
|
||||
return Ply.dialog('prompt', { effect: 'none:1' }, { |
||||
title: "???", |
||||
form: { email: "E-mail" } |
||||
}).then(function (ui) { |
||||
equal(ui.by, 'submit', 'ui.by'); |
||||
equal(ui.state, true, 'ui.state'); |
||||
equal(ui.context.val('email'), 'xx@yy.zz'); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('dialog("confirm") with YES/NO', function () { |
||||
setTimeout(function () { |
||||
var el = Ply.stack.last.wrapEl; |
||||
simulateEvent(el.getElementsByTagName('button')[0], 'click'); |
||||
}, 50); |
||||
|
||||
return Ply.dialog("confirm", { effect: 'none:1' }, { ok: 'YES', cancel: 'NO' }).then(function (ui) { |
||||
equal(ui.layer.layerEl.getElementsByTagName('button')[0].innerHTML, 'YES', 'ok'); |
||||
equal(ui.layer.layerEl.getElementsByTagName('button')[1].innerHTML, 'NO', 'cancel'); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('dialog({ steps })', function () { |
||||
var log = []; |
||||
|
||||
return Ply.dialog({ |
||||
'foo': { |
||||
data: { text: 'foo' }, |
||||
options: { effect: 'none:1' }, |
||||
prepare: function (data) { |
||||
data.text += '!'; |
||||
}, |
||||
next: 'baz' |
||||
}, |
||||
'bar': { |
||||
data: { text: 'bar' } |
||||
}, |
||||
'baz': { |
||||
ui: 'confirm', |
||||
data: { text: 'baz' }, |
||||
back: 'bar' |
||||
} |
||||
}, { |
||||
progress: function (ui) { |
||||
log.push(ui.name + ':' + ui.state); |
||||
|
||||
setTimeout(function () { |
||||
simulateEvent( |
||||
ui.layer.layerEl.getElementsByTagName('button')[1] |
||||
|| ui.layer.layerEl.getElementsByTagName('button')[0], |
||||
'click'); |
||||
}, 10); |
||||
} |
||||
}).then(function () { |
||||
equal(log.join('\n'), [ |
||||
'foo:undefined', |
||||
'baz:true', |
||||
'bar:false' |
||||
].join('\n')); |
||||
}); |
||||
}); |
||||
|
||||
|
||||
promiseTest('factory.use()', function () { |
||||
Ply.factory('test', function (options, data, resolve) { |
||||
Ply.factory.use('alert', options, { |
||||
text: '!?', |
||||
ok: 'Y' |
||||
}, resolve); |
||||
}); |
||||
|
||||
return Ply.create("test").then(function (layer) { |
||||
equal(layer.context.getEl('el').innerHTML, '!?'); |
||||
equal(layer.layerEl.getElementsByTagName('button')[0].innerHTML, 'Y'); |
||||
}); |
||||
}); |
||||
})(Ply); |
@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html> |
||||
<html xmlns="http://www.w3.org/1999/html"> |
||||
<head> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
||||
|
||||
<title>Ply :: Tests</title> |
||||
|
||||
<!--script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> |
||||
<script src="http://code.jquery.com/qunit/qunit-git.js"></script> |
||||
<link href="http://code.jquery.com/qunit/qunit-git.css" rel="stylesheet"/--> |
||||
|
||||
<script> |
||||
if (!window.jQuery) { |
||||
document.write('<script src="http://local.git/js/jquery.dev.js"><' + '/script>'); |
||||
document.write('<script src="http://local.git/js/qunit/qunit.js"><' + '/script>'); |
||||
document.write('<link href="http://local.git/js/qunit/qunit.css" rel="stylesheet"/>'); |
||||
} |
||||
|
||||
if (/state=2/.test(location)) { |
||||
// document.write('<script src="http://local.git/JSSDK/Promise/Promise.js"><' + '/script>'); |
||||
} |
||||
</script> |
||||
|
||||
<script> |
||||
(function () { |
||||
var defaultOptions = { |
||||
x: 0, |
||||
y: 0, |
||||
button: 0, |
||||
ctrlKey: false, |
||||
altKey: false, |
||||
shiftKey: false, |
||||
metaKey: false, |
||||
bubbles: true, |
||||
cancelable: true |
||||
}; |
||||
|
||||
|
||||
var eventMatchers = { |
||||
'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|input|keydown|keyup|blur|resize|scroll)$/, |
||||
'MouseEvents': /^(?:click|dblclick|mouse(?:down|up|over|move|out))$/ |
||||
}; |
||||
|
||||
|
||||
window.isPhantomJS = /phantomjs/i.test(navigator.userAgent); |
||||
|
||||
window.simulateEvent = function (element, eventName, opts) { |
||||
var options = $.extend({}, defaultOptions, opts || {}); |
||||
var oEvent, eventType = null; |
||||
|
||||
for (var name in eventMatchers) { |
||||
if (eventMatchers[name].test(eventName)) { |
||||
eventType = name; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!eventType) { |
||||
throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported'); |
||||
} |
||||
|
||||
if (document.createEvent) { |
||||
oEvent = document.createEvent(eventType); |
||||
if (eventType == 'HTMLEvents') { |
||||
oEvent.initEvent(eventName, options.bubbles, options.cancelable); |
||||
} |
||||
else { |
||||
oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, window, |
||||
options.button, options.x, options.y, options.x, options.y, |
||||
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element); |
||||
} |
||||
$.extend(oEvent, options); |
||||
element.dispatchEvent(oEvent); |
||||
} |
||||
else { |
||||
options.clientX = options.x; |
||||
options.clientY = options.y; |
||||
var evt = document.createEventObject(); |
||||
oEvent = $.extend(evt, options); |
||||
element.fireEvent('on' + eventName, oEvent); |
||||
} |
||||
return element; |
||||
}; |
||||
|
||||
|
||||
window.promiseTest = function (name, promise) { |
||||
asyncTest(name, function () { |
||||
promise().then(function () { |
||||
start(); |
||||
}, function (err) { |
||||
equal([err, err.stack], null, 'fail'); |
||||
start(); |
||||
}); |
||||
}); |
||||
}; |
||||
})(); |
||||
</script> |
||||
|
||||
</head> |
||||
</body> |
||||
|
||||
<h1 id="qunit-header">Ply :: tests</h1> |
||||
<h2 id="qunit-banner"></h2> |
||||
<div id="qunit-testrunner-toolbar"></div> |
||||
<h2 id="qunit-userAgent"></h2> |
||||
<ol id="qunit-tests"></ol> |
||||
<div id="playground"></div> |
||||
|
||||
|
||||
<!-- lib:css --> |
||||
<link href="../ply.css" rel="stylesheet"/> |
||||
|
||||
<!-- lib:src --> |
||||
<script src="../Ply.js"></script> |
||||
<script src="../Ply.ui.js"></script> |
||||
|
||||
<!-- lib:tests --> |
||||
<script src="./Ply.tests.js"></script> |
||||
<script src="./Ply.dom.tests.js"></script> |
||||
<script src="./Ply.effects.tests.js"></script> |
||||
<script src="./Ply.ui.tests.js"></script> |
||||
|
||||
<script> |
||||
if (parent.resolveTest) { |
||||
test('end', function () { |
||||
expect(0); |
||||
parent.resolveTest(); |
||||
}); |
||||
} |
||||
</script> |
||||
</body> |
||||
</html> |
Loading…
Reference in new issue