From 7adcb81e4f83f98c468889aaa5a85558ba88c770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Mon, 25 Jan 2016 17:45:33 +0100 Subject: Initial commit --- sources/samples/js/sample.js | 54 ++++ sources/samples/js/sf.js | 673 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 727 insertions(+) create mode 100644 sources/samples/js/sample.js create mode 100644 sources/samples/js/sf.js (limited to 'sources/samples/js') diff --git a/sources/samples/js/sample.js b/sources/samples/js/sample.js new file mode 100644 index 00000000..355b4cd7 --- /dev/null +++ b/sources/samples/js/sample.js @@ -0,0 +1,54 @@ +/** + * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or http://ckeditor.com/license + */ + +/* exported initSample */ + +if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) + CKEDITOR.tools.enableHtml5Elements( document ); + +// The trick to keep the editor in the sample quite small +// unless user specified own height. +CKEDITOR.config.height = 150; +CKEDITOR.config.width = 'auto'; + +var initSample = ( function() { + var wysiwygareaAvailable = isWysiwygareaAvailable(), + isBBCodeBuiltIn = !!CKEDITOR.plugins.get( 'bbcode' ); + + return function() { + var editorElement = CKEDITOR.document.getById( 'editor' ); + + // :((( + if ( isBBCodeBuiltIn ) { + editorElement.setHtml( + 'Hello world!\n\n' + + 'I\'m an instance of [url=http://ckeditor.com]CKEditor[/url].' + ); + } + + // Depending on the wysiwygare plugin availability initialize classic or inline editor. + if ( wysiwygareaAvailable ) { + CKEDITOR.replace( 'editor' ); + } else { + editorElement.setAttribute( 'contenteditable', 'true' ); + CKEDITOR.inline( 'editor' ); + + // TODO we can consider displaying some info box that + // without wysiwygarea the classic editor may not work. + } + }; + + function isWysiwygareaAvailable() { + // If in development mode, then the wysiwygarea must be available. + // Split REV into two strings so builder does not replace it :D. + if ( CKEDITOR.revision == ( '%RE' + 'V%' ) ) { + return true; + } + + return !!CKEDITOR.plugins.get( 'wysiwygarea' ); + } +} )(); + +// %LEAVE_UNMINIFIED% %REMOVE_LINE% diff --git a/sources/samples/js/sf.js b/sources/samples/js/sf.js new file mode 100644 index 00000000..2cf18e96 --- /dev/null +++ b/sources/samples/js/sf.js @@ -0,0 +1,673 @@ +/** + * @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 \ No newline at end of file -- cgit v1.2.3