123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673 |
- /**
- * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md or http://ckeditor.com/license
- */
- /* exported SF */
- 'use strict';
- var SF = ( function() {
- var SF = {};
- SF.attachListener = function( elem, evtName, callback ) {
- if ( elem.addEventListener ) {
- elem.addEventListener( evtName, callback, false );
- } else if ( elem.attachEvent ) {
- elem.attachEvent( 'on' + evtName , function() {
- callback.apply( elem, arguments );
- } );
- } else {
- throw new Error( 'Could not attach event.' );
- }
- };
- SF.indexOf = ( function() {
- var indexOf = Array.prototype.indexOf;
- if ( indexOf === 'function' ) {
- return function( arr, elem ) {
- return indexOf.call( arr, elem );
- };
- } else {
- return function( arr, elem ) {
- var max = arr.length;
- for ( var i = 0; i < max; i++ ) {
- if ( arr[ i ] === elem ) {
- return i;
- }
- }
- return -1;
- };
- }
- }() );
- SF.accept = function( node, visitor ) {
- var children;
- // Handling node as a node and array
- if ( node.children ) {
- children = node.children;
- visitor( node );
- } else if ( typeof node.length === 'number' ) {
- children = node;
- }
- var i = children ? ( children.length || 0 ) : 0;
- while ( i-- ) {
- SF.accept( children[ i ], visitor );
- }
- };
- SF.getByClass = ( function( ) {
- var getByClass = document.getElementsByClassName;
- if ( typeof getByClass === 'function' ) {
- return function( root, className ) {
- if ( typeof root === 'string' ) {
- className = root;
- root = document;
- }
- return getByClass.call( root, className );
- };
- }
- return function( root, className ) {
- if ( typeof root === 'string' ) {
- className = root;
- root = document.getElementsByTagName( 'html' )[ 0 ];
- }
- var results = [];
- SF.accept( root, function( elem ) {
- if ( SF.classList.contains( elem, className ) ) {
- results.push( elem );
- }
- } );
- return results;
- };
- }() );
- SF.classList = {};
- SF.classList.add = function( elem, className ) {
- var classes = parseClasses( elem );
- classes.push( className );
- elem.attributes.setNamedItem( createClassAttr( classes ) );
- };
- SF.classList.remove = function( elem, className ) {
- var classes = parseClasses( elem, className ),
- foundAt = SF.indexOf( classes, className );
- if ( foundAt === -1 ) {
- return;
- }
- classes.splice( foundAt, 1 );
- elem.attributes.setNamedItem( createClassAttr( classes ) );
- };
- SF.classList.contains = function( elem, className ) {
- return findIndex( elem, className ) !== -1;
- };
- SF.classList.toggle = function( elem, className ) {
- this.contains( elem, className ) ? this.remove( elem, className ) : this.add( elem, className );
- };
- function findIndex( elem, className ) {
- return SF.indexOf( parseClasses( elem ), className );
- }
- function parseClasses( elem ) {
- var classAttr = elem.attributes ? elem.attributes.getNamedItem( 'class' ) : null;
- return classAttr ? classAttr.value.split( ' ' ) : [];
- }
- function createClassAttr( classesArray ) {
- var attr = document.createAttribute( 'class' );
- attr.value = classesArray.join( ' ' );
- return attr;
- }
- return SF;
- }() );
- /* global SF, picoModal */
- 'use strict';
- ( function() {
- // Purges all styles in passed object.
- function purgeStyles( styles ) {
- for ( var i in styles ) {
- delete styles[ i ];
- }
- }
- SF.modal = function( config ) {
- // Modal should use the same style set as the rest of the page (.content component).
- config.modalClass = 'modal content';
- config.closeClass = 'modal-close';
- // Purge all pre-defined pico styles. Use the lessfile instead.
- config.modalStyles = purgeStyles;
- // Close button styles are customized via lessfile.
- config.closeStyles = purgeStyles;
- var userDefinedAfterCreate = config.afterCreate,
- userDefinedAfterClose = config.afterClose;
- // Close modal on ESC key.
- function onKeyDown( event ) {
- if ( event.keyCode == 27 ) {
- modal.close();
- }
- }
- // Use afterCreate as a config option rather than function chain.
- config.afterCreate = function( modal ) {
- userDefinedAfterCreate && userDefinedAfterCreate( modal );
- window.addEventListener( 'keydown', onKeyDown );
- };
- // Use afterClose as a config option rather than function chain.
- config.afterClose = function( modal ) {
- userDefinedAfterClose && userDefinedAfterClose( modal );
- window.removeEventListener( 'keydown', onKeyDown );
- };
- var modal = new picoModal( config )
- .afterCreate( config.afterCreate )
- .afterClose( config.afterClose );
- return modal;
- };
- } )();
- 'use strict';
- ( function() {
- // All .tree-a elements in DOM.
- var expanders = SF.getByClass( 'toggler' );
- var i = expanders.length;
- while ( i-- ) {
- var expander = expanders[ i ];
- SF.attachListener( expander, 'click', function() {
- var containsIcon = SF.classList.contains( this, 'icon-toggler-expanded' ) || SF.classList.contains( this, 'icon-toggler-collapsed' ),
- related = document.getElementById( this.getAttribute( 'data-for' ) );
- SF.classList.toggle( this, 'collapsed' );
- if ( SF.classList.contains( this, 'collapsed' ) ) {
- SF.classList.add( related, 'collapsed' );
- if ( containsIcon ) {
- SF.classList.remove( this, 'icon-toggler-expanded' );
- SF.classList.add( this, 'icon-toggler-collapsed' );
- }
- } else {
- SF.classList.remove( related, 'collapsed' );
- if ( containsIcon ) {
- SF.classList.remove( this, 'icon-toggler-collapsed' );
- SF.classList.add( this, 'icon-toggler-expanded' );
- }
- }
- } );
- }
- } )();
- /* global SF */
- 'use strict';
- ( function() {
- // All .tree-a elements in DOM.
- var trees = SF.getByClass( 'tree-a' );
- for ( var i = trees.length; i--; ) {
- var tree = trees[ i ];
- SF.attachListener( tree, 'click', function( evt ) {
- var target = evt.target || evt.srcElement;
- // Collapse or expand item groups.
- if ( target.nodeName === 'H2' && !SF.classList.contains( target, 'tree-a-no-sub' ) ) {
- SF.classList.toggle( target, 'tree-a-active' );
- }
- } );
- }
- } )();
- // jshint ignore:start
- // jscs:disable
- /**
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- /**
- * A self-contained modal library
- */
- (function(window, document) {
- "use strict";
- /** Returns whether a value is a dom node */
- function isNode(value) {
- if ( typeof Node === "object" ) {
- return value instanceof Node;
- }
- else {
- return value &&
- typeof value === "object" &&
- typeof value.nodeType === "number";
- }
- }
- /** Returns whether a value is a string */
- function isString(value) {
- return typeof value === "string";
- }
- /**
- * Generates observable objects that can be watched and triggered
- */
- function observable() {
- var callbacks = [];
- return {
- watch: callbacks.push.bind(callbacks),
- trigger: function( modal ) {
- var unprevented = true;
- var event = {
- preventDefault: function preventDefault () {
- unprevented = false;
- }
- };
- for (var i = 0; i < callbacks.length; i++) {
- callbacks[i](modal, event);
- }
- return unprevented;
- }
- };
- }
- /**
- * A small interface for creating and managing a dom element
- */
- function Elem( elem ) {
- this.elem = elem;
- }
- /**
- * Creates a new div
- */
- Elem.div = function ( parent ) {
- var elem = document.createElement('div');
- (parent || document.body).appendChild(elem);
- return new Elem(elem);
- };
- Elem.prototype = {
- /** Creates a child of this node */
- child: function () {
- return Elem.div(this.elem);
- },
- /** Applies a set of styles to an element */
- stylize: function(styles) {
- styles = styles || {};
- if ( typeof styles.opacity !== "undefined" ) {
- styles.filter =
- "alpha(opacity=" + (styles.opacity * 100) + ")";
- }
- for (var prop in styles) {
- if (styles.hasOwnProperty(prop)) {
- this.elem.style[prop] = styles[prop];
- }
- }
- return this;
- },
- /** Adds a class name */
- clazz: function (clazz) {
- this.elem.className += " " + clazz;
- return this;
- },
- /** Sets the HTML */
- html: function (content) {
- if ( isNode(content) ) {
- this.elem.appendChild( content );
- }
- else {
- this.elem.innerHTML = content;
- }
- return this;
- },
- /** Adds a click handler to this element */
- onClick: function(callback) {
- this.elem.addEventListener('click', callback);
- return this;
- },
- /** Removes this element from the DOM */
- destroy: function() {
- document.body.removeChild(this.elem);
- },
- /** Hides this element */
- hide: function() {
- this.elem.style.display = "none";
- },
- /** Shows this element */
- show: function() {
- this.elem.style.display = "block";
- },
- /** Sets an attribute on this element */
- attr: function ( name, value ) {
- this.elem.setAttribute(name, value);
- return this;
- },
- /** Executes a callback on all the ancestors of an element */
- anyAncestor: function ( predicate ) {
- var elem = this.elem;
- while ( elem ) {
- if ( predicate( new Elem(elem) ) ) {
- return true;
- }
- else {
- elem = elem.parentNode;
- }
- }
- return false;
- }
- };
- /** Generates the grey-out effect */
- function buildOverlay( getOption, close ) {
- return Elem.div()
- .clazz("pico-overlay")
- .clazz( getOption("overlayClass", "") )
- .stylize({
- display: "block",
- position: "fixed",
- top: "0px",
- left: "0px",
- height: "100%",
- width: "100%",
- zIndex: 10000
- })
- .stylize(getOption('overlayStyles', {
- opacity: 0.5,
- background: "#000"
- }))
- .onClick(function () {
- if ( getOption('overlayClose', true) ) {
- close();
- }
- });
- }
- /** Builds the content of a modal */
- function buildModal( getOption, close ) {
- var width = getOption('width', 'auto');
- if ( typeof width === "number" ) {
- width = "" + width + "px";
- }
- var elem = Elem.div()
- .clazz("pico-content")
- .clazz( getOption("modalClass", "") )
- .stylize({
- display: 'block',
- position: 'fixed',
- zIndex: 10001,
- left: "50%",
- top: "50px",
- width: width,
- '-ms-transform': 'translateX(-50%)',
- '-moz-transform': 'translateX(-50%)',
- '-webkit-transform': 'translateX(-50%)',
- '-o-transform': 'translateX(-50%)',
- 'transform': 'translateX(-50%)'
- })
- .stylize(getOption('modalStyles', {
- backgroundColor: "white",
- padding: "20px",
- borderRadius: "5px"
- }))
- .html( getOption('content') )
- .attr("role", "dialog")
- .onClick(function (event) {
- var isCloseClick = new Elem(event.target)
- .anyAncestor(function (elem) {
- return /\bpico-close\b/.test(elem.elem.className);
- });
- if ( isCloseClick ) {
- close();
- }
- });
- return elem;
- }
- /** Builds the close button */
- function buildClose ( elem, getOption ) {
- if ( getOption('closeButton', true) ) {
- return elem.child()
- .html( getOption('closeHtml', "×") )
- .clazz("pico-close")
- .clazz( getOption("closeClass") )
- .stylize( getOption('closeStyles', {
- borderRadius: "2px",
- cursor: "pointer",
- height: "15px",
- width: "15px",
- position: "absolute",
- top: "5px",
- right: "5px",
- fontSize: "16px",
- textAlign: "center",
- lineHeight: "15px",
- background: "#CCC"
- }) );
- }
- }
- /** Builds a method that calls a method and returns an element */
- function buildElemAccessor( builder ) {
- return function () {
- return builder().elem;
- };
- }
- /**
- * Displays a modal
- */
- function picoModal(options) {
- if ( isString(options) || isNode(options) ) {
- options = { content: options };
- }
- var afterCreateEvent = observable();
- var beforeShowEvent = observable();
- var afterShowEvent = observable();
- var beforeCloseEvent = observable();
- var afterCloseEvent = observable();
- /**
- * Returns a named option if it has been explicitly defined. Otherwise,
- * it returns the given default value
- */
- function getOption ( opt, defaultValue ) {
- var value = options[opt];
- if ( typeof value === "function" ) {
- value = value( defaultValue );
- }
- return value === undefined ? defaultValue : value;
- }
- /** Hides this modal */
- function forceClose () {
- shadowElem().hide();
- modalElem().hide();
- afterCloseEvent.trigger(iface);
- }
- /** Gracefully hides this modal */
- function close () {
- if ( beforeCloseEvent.trigger(iface) ) {
- forceClose();
- }
- }
- /** Wraps a method so it returns the modal interface */
- function returnIface ( callback ) {
- return function () {
- callback.apply(this, arguments);
- return iface;
- };
- }
- // The constructed dom nodes
- var built;
- /** Builds a method that calls a method and returns an element */
- function build ( name ) {
- if ( !built ) {
- var modal = buildModal(getOption, close);
- built = {
- modal: modal,
- overlay: buildOverlay(getOption, close),
- close: buildClose(modal, getOption)
- };
- afterCreateEvent.trigger(iface);
- }
- return built[name];
- }
- var modalElem = build.bind(window, 'modal');
- var shadowElem = build.bind(window, 'overlay');
- var closeElem = build.bind(window, 'close');
- var iface = {
- /** Returns the wrapping modal element */
- modalElem: buildElemAccessor(modalElem),
- /** Returns the close button element */
- closeElem: buildElemAccessor(closeElem),
- /** Returns the overlay element */
- overlayElem: buildElemAccessor(shadowElem),
- /** Shows this modal */
- show: function () {
- if ( beforeShowEvent.trigger(iface) ) {
- shadowElem().show();
- closeElem();
- modalElem().show();
- afterShowEvent.trigger(iface);
- }
- return this;
- },
- /** Hides this modal */
- close: returnIface(close),
- /**
- * Force closes this modal. This will not call beforeClose
- * events and will just immediately hide the modal
- */
- forceClose: returnIface(forceClose),
- /** Destroys this modal */
- destroy: function () {
- modalElem = modalElem().destroy();
- shadowElem = shadowElem().destroy();
- closeElem = undefined;
- },
- /**
- * Updates the options for this modal. This will only let you
- * change options that are re-evaluted regularly, such as
- * `overlayClose`.
- */
- options: function ( opts ) {
- options = opts;
- },
- /** Executes after the DOM nodes are created */
- afterCreate: returnIface(afterCreateEvent.watch),
- /** Executes a callback before this modal is closed */
- beforeShow: returnIface(beforeShowEvent.watch),
- /** Executes a callback after this modal is shown */
- afterShow: returnIface(afterShowEvent.watch),
- /** Executes a callback before this modal is closed */
- beforeClose: returnIface(beforeCloseEvent.watch),
- /** Executes a callback after this modal is closed */
- afterClose: returnIface(afterCloseEvent.watch)
- };
- return iface;
- }
- if ( typeof window.define === "function" && window.define.amd ) {
- window.define(function () {
- return picoModal;
- });
- }
- else {
- window.picoModal = picoModal;
- }
- }(window, document));
- // jscs:enable
- // jshint ignore:end
|