# Ply Amazing layer/modal/dialog system. Wow! ## Features * Demo: [http://rubaxa.github.io/Ply/](http://rubaxa.github.io/Ply/) * Support browsers: Chrome 20+, FireFox 20+, Safari 6+, Opera 12+, IE8+ * No jQuery (but then need [Promise](https://gist.github.com/RubaXa/8501359) polyfill) * More than 90% [test code coverage](http://rubaxa.github.io/Ply/tests/) * Preloading content before displaying * Smart focus on form elements * [ES6 syntax](https://github.com/termi/es6-transpiler) ## Base usage Include [ply.css](ply.css) in `` (optional) ```html ``` Create a dialog: ```js Ply.dialog("alert", "Wow!").always(function (ui) { ui.state; // true — "OK", false — "cancel" ui.by; // submit, overlay, esc, "x" ui.widget; // Ply instance }); //or Ply.dialog("confirm", "Do you like it?") .done(function (ui) { // OK }) .fail(function (ui) { // Cancel }) .always(function (ui) { if (ui.state) { // Clicked "OK" } else { // Clicked "Cancel" // details: `ui.by` — "cancel", "overlay", "esc", "x" } }); ``` --- ## Dialogs ```js Ply.dialog({ "init-state": { ui: "alert", data: "Wow!", next: "other-step" nextEffect: "3d-flip[180,-180]" }, "other-step": { ui: "confirm", data: { text: "What's next?", ok: "Exit", // button text cancel: "Back" }, back: "init-state", backEffect: "3d-flip[-180,180]" } }).always(function (ui) { if (ui.state) { // OK } else { // Cancel // ui.by — 'overlay', 'x', 'esc' } }) ``` --- ## Low-level ##### new Ply(el[, options]) * el:`String|HTMLElement` — content of layer * options:`Object` — layer options ##### new Ply(options) * options:`Object` — layer options ```js var ply = new Ply({ el: "...", // HTML-content effect: "fade", // or ["open-effect:duration", "close-effect:duration"] layer: {}, // default css overlay: { // defaults css opacity: 0.6, backgroundColor: "#000" }, flags: { // defaults closeBtn: true, // presence close button "✖" bodyScroll: false, // disable scrollbar at body closeByEsc: true, // close by press on `Esc` key closeByOverlay: true, // close by click on the overlay hideLayerInStack: true, // hide the layer if it is not the first in the stack visibleOverlayInStack: false // visibility overlay, if the layer is not the first in the stack }, // Callback oninit: function (ply) {}, onopen: function (ply) {}, onclose: function (ply) {}, ondestory: function (ply) {}, onaction: function (ui) {}, }); // And ply.open().always(function () { ply.swap({ el: ".." }, "3d-flip").always(function () { ply.close(); }); }); ``` ##### open([effect]):`Promise` ##### close(effect):`Promise` ##### swap(layer[, effect]):`Promise` Swapping one layer to another ##### innerSwap(layer[, effect]):`Promise` Swapping the content of one layer to another ##### destroy() Destroy layer --- ## Preset effects - fade - scale - fall - slide - 3d-flip - 3d-sign ### Combined effects ```js Ply.dialog("alert", { effect: ["fade", "scale"] }, "Fade & scale"); ``` ### Custom effects ```js Ply.effects["my-effect"] = { open: { layer: "fade-in", overlay: "background-in" }, close: { layer: "fade-out", overlay: "background-out" } }; Ply.effects["background-in"] = { "from": { opacity: 0, backgroundColor: "red" }, "to": { opacity: 1, backgroundColor: "white" } }; Ply.effects["background-out"] = { "from": { opacity: 1, backgroundColor: "white" }, "to": { opacity: 0, backgroundColor: "green" } }; ``` --- ## Ply.stack * last:`Ply|null` * length:`Number` --- ## Ply.support * transition:`String|Boolean` * transform:`String|Boolean` * perspective:`String|Boolean` * transformStyle:`String|Boolean` * transformOrigin:`String|Boolean` * backfaceVisibility:`String|Boolean` --- ## Ply.lang (localization) * ok:`String` — "OK" * cancel:`String` — "Cancel" * cross:`String` — "✖" --- ## Ply.defaults * layer:`Object` — css * overlay:`Object` — style overlay * opacity:Number — default `0.6` * backgroundColor:String — default `rgb(0, 0, 0)'` * flags:`Object` * closeBtn:`Boolean` — presence close button "✖" * bodyScroll:Boolean — disable scrollbars, default `false` * closeByEsc:`Boolean` — closing the layer by pressing the `esc` key, default `true` * closeByOverlay:`Boolean` — closing the layer by clicking on the overlay, default `true` * hideLayerInStack:`Boolean` — hide the layer if it is not the first in the stack * visibleOverlayInStack:`Boolean` — visibility overlay, if the layer is not the first in the stack --- ## Ply.dom ##### build(tag:`String|Object`):`HTMLElement` ```js Ply.build(); //
Ply.build("input"); // Ply.build(".foo"); //
Ply.build(".foo.bar"); //
Ply.build({ // tag: "input.foo", type: "password", css: { padding: "10px" }, maxlength: 32 }); Ply.build({ text: "?" }); //
<i>?</i>
Ply.build({ html: "!" }); //
!
``` ##### append(parent:`HTMLElement`, el:`HTMLElement`) ##### remove(el:`HTMLElement`) ##### addEvent(el:`HTMLElement`, name:`String`, fn:`Function`) ##### removeEvent(el:`HTMLElement`, name:`String`, fn:`Function`) --- ## Create a dialog template ##### Ply.ui(name):`HTMLElement` * name:`String` — ui-element name ```js var el = Ply.ui("btn", { title: "click me", value: "Wow!" }) ``` ##### Ply.ui.factory(name, factory) * name:`String` — ui-element name * factory:`Function` — callback ```js Ply.ui.factory("btn", function (data, children) { // data:`Object` // children:`HTMLElement` return { "tag": ".btn", "text": data.value }; }); // or button with icon (optional) Ply.ui.factory("btn", function (data, children) { return { "tag": ".btn", "title": data.title "children": [ data.icon && { "tag": "span.glyphicon.glyphicon-" + data.icon }, { "tag": "span", "text": data.value } ] }; }); ``` ##### Ply.factory(name, factory) * name:`String` — template name * factory:`Function` — callback ```js Ply.factory("subscribe", function (options, data, resolve) { // options — ply options // data — user data // resolve — done function resolve({ "header": "Spam subscribe", "content": { "fieldset": { "name": { label: "Username", value: data.name }, "email": { label: "E-mail", value: data.email }, "agree": true } }, ctrls: { "ok": true, "cancel": "abort" // for example } }); // OR var element = template(data); resolve(element); }); Ply.ui.factory("fieldset", function (data, children) { return { tag: ".fieldset", children: children }; }); // Default element in `fieldset` Ply.ui.factory("fieldset *", function (data) { var uid = Math.round(Math.random() * 1e9).toString(36); return { tag: ".field", children: [ { tag: "label", forHtml: uid, text: data.label }, { tag: "input", id: uid, name: data.name, value: data.value } ] }; }); Ply.ui.factory("fieldset agree", function (data) { var uid = Math.round(Math.random() * 1e9).toString(36); return { tag: ".field", children: [ { tag: "input", type: "checkbox", id: uid, name: "agree", value: "Y" }, { tag: "label", forHtml: uid, text: "I agree." } ] }; }); // Usage Ply.dialog("subscribe", { "name": "RubaXa", "email": "trash@rubaxa.org", }); ``` --- ## Development * `grunt watch` — dev mode * `grunt build` — assembly project --- ## Changelog * Added `ply-loading` * `ui.layer` -> `ui.widget` * Added a `on` prefix to all callbacks ##### 0.4.0 * + 'always' method (using inheritance «Promise»). * + Modularization ##### 0.3.0 * #1: Testing and documentation * #3: Stack features