MDL-38904 Theme/JavaScript: Tidy up bootstrap JS

This commit is contained in:
Andrew Nicols
2013-04-09 23:50:51 +01:00
parent 422f68fb86
commit 7e98ebd5ca
13 changed files with 2497 additions and 41 deletions
-224
View File
@@ -1,224 +0,0 @@
YUI.add('gallery-bootstrap-collapse', function(Y) {
/**
A Plugin which provides collapsing/expanding behaviors on a Node with
compatible syntax and markup from Twitter's Bootstrap project.
@module gallery-bootstrap-collapse
**/
/**
A Plugin which provides collapsing and expanding behaviors on a Node with
compatible syntax and markup from Twitter's Bootstrap project.
It possible to have dynamic behaviors without incorporating any
JavaScript by setting <code>data-toggle=collapse</code> on any element.
However, it can be manually plugged into any node or node list.
@example
var node = Y.one('.someNode');
node.plug( Y.Bootstrap.Collapse, config );
node.collapse.show();
@class Bootstrap.Collapse
**/
function CollapsePlugin(config) {
CollapsePlugin.superclass.constructor.apply(this, arguments);
}
CollapsePlugin.NAME = 'Bootstrap.Collapse';
CollapsePlugin.NS = 'collapse';
Y.extend(CollapsePlugin, Y.Plugin.Base, {
defaults : {
duration : 0.25,
easing : 'ease-in',
showClass : 'in',
hideClass : 'out',
groupSelector : '> .accordion-group > .in'
},
transitioning: false,
initializer : function(config) {
this._node = config.host;
this.config = Y.mix( config, this.defaults );
this.publish('show', { preventable : true, defaultFn : this.show });
this.publish('hide', { preventable : true, defaultFn : this.hide });
this._node.on('click', this.toggle, this);
},
_getTarget: function() {
var node = this._node,
container;
if ( node.getData('target') ) {
container = Y.one( node.getData('target') );
}
else if ( node.getAttribute('href').indexOf('#') >= 0 ) {
Y.log('No target, looking at href: ' + node.getAttribute('href'), 'debug', 'Bootstrap.Collapse');
container = Y.one( node.getAttribute('href').substr( node.getAttribute('href').indexOf('#') ) );
}
return container;
},
/**
* @method hide
* @description Hide the collapsible target, specified by the host's
* <code>data-target</code> or <code>href</code> attribute.
*/
hide: function() {
var showClass = this.config.showClass,
hideClass = this.config.hideClass,
node = this._getTarget();
if ( this.transitioning ) {
return;
}
if ( node ) {
this._hideElement(node);
}
},
/**
* @method show
* @description Show the collapsible target, specified by the host's
* <code>data-target</code> or <code>href</code> attribute.
*/
show: function() {
var showClass = this.config.showClass,
hideClass = this.config.hideClass,
node = this._getTarget(),
host = this._node,
self = this,
parent,
group_selector = this.config.groupSelector;
if ( this.transitioning ) {
return;
}
if ( host.getData('parent') ) {
parent = Y.one( host.getData('parent') );
if ( parent ) {
parent.all(group_selector).each( function(el) {
Y.log('Hiding element: ' + el, 'debug', 'Bootstrap.Collapse');
self._hideElement(el);
});
}
}
this._showElement(node);
},
/**
@method toggle
@description Toggle the state of the collapsible target, specified
by the host's <code>data-target</code> or <code>href</code>
attribute. Calls the <code>show</code> or <code>hide</code> method.
**/
toggle : function(e) {
if ( e && Y.Lang.isFunction(e.preventDefault) ) {
e.preventDefault();
}
var target = this._getTarget();
if ( target.hasClass( this.config.showClass ) ) {
this.fire('hide');
} else {
this.fire('show');
}
},
/**
@method _transition
@description Handles the transition between showing and hiding.
@protected
@param node {Node} node to apply transitions to
@param method {String} 'hide' or 'show'
**/
_transition : function(node, method) {
var self = this,
config = this.config,
duration = config.duration,
easing = config.easing,
// If we are hiding, then remove the show class.
removeClass = method === 'hide' ? config.showClass : config.hideClass,
// And if we are hiding, add the hide class.
addClass = method === 'hide' ? config.hideClass : config.showClass,
to_height = method === 'hide' ? 0 : null,
event = method === 'hide' ? 'hidden' : 'shown',
complete = function() {
node.removeClass(removeClass);
node.addClass(addClass);
self.transitioning = false;
this.fire( event );
};
if ( to_height === null ) {
to_height = 0;
node.all('> *').each(function(el) {
to_height += el.get('scrollHeight');
});
}
this.transitioning = true;
node.transition({
height : to_height +'px',
duration : duration,
easing : easing
}, complete);
},
/**
@method _hideElement
@description Calls the <code>_transition</code> method to hide a node.
@protected
@param node {Node} node to hide.
**/
_hideElement : function(node) {
this._transition(node, 'hide');
/*
var showClass = this.showClass,
hideClass = this.hideClass;
node.removeClass(showClass);
node.addClass(hideClass);
*/
},
/**
@method _showElement
@description Calls the <code>_transition</code> method to show a node.
@protected
@param node {Node} node to show.
**/
_showElement : function(node) {
this._transition(node, 'show');
/*
var showClass = this.showClass,
hideClass = this.hideClass;
node.removeClass(hideClass);
node.addClass(showClass);
*/
}
});
Y.namespace('Bootstrap').Collapse = CollapsePlugin;
}, '@VERSION@' ,{requires:['plugin','transition','event','event-delegate']});
;
-115
View File
@@ -1,115 +0,0 @@
YUI.add('gallery-bootstrap-dropdown', function(Y) {
/**
A Plugin which provides dropdown behaviors for dropdown buttons and menu
groups. This utilizes the markup from the Twitter Bootstrap Project.
@module gallery-bootstrap-dropdown
**/
/**
A Plugin which provides dropdown behaviors for dropdown buttons and menu
groups. This utilizes the markup from the Twitter Bootstrap Project.
To automatically gain this functionality, you can simply add the
<code>data-toggle=dropdown</code> attribute to any element.
It can also be plugged into any node or node list.
@example
var node = Y.one('.someNode');
node.plug( Y.Bootstrap.Dropdown );
node.dropdown.show();
@class Bootstrap.Dropdown
**/
var NS = Y.namespace('Bootstrap');
function DropdownPlugin(config) {
DropdownPlugin.superclass.constructor.apply(this, arguments);
}
DropdownPlugin.NAME = 'Bootstrap.Dropdown';
DropdownPlugin.NS = 'dropdown';
Y.extend( DropdownPlugin, Y.Plugin.Base, {
defaults : {
className : 'open',
target : 'target',
selector : ''
},
initializer : function(config) {
this._node = config.host;
this.config = Y.mix( config, this.defaults );
this.publish('show', { preventable : true, defaultFn : this.show });
this.publish('hide', { preventable : true, defaultFn : this.hide });
this._node.on('click', this.toggle, this);
},
toggle : function() {
var target = this.getTarget(),
className = this.config.className;
target.toggleClass( className );
target.once('clickoutside', function(e) {
target.toggleClass( className );
});
},
show : function() {
this.getTarget().addClass( this.config.className );
},
hide : function() {
this.getTarget().removeClass( this.config.className );
},
open : function() {
this.getTarget().addClass( this.config.className );
},
close : function() {
this.getTarget().removeClass( this.config.className );
},
/**
@method getTarget
@description Fetches a Y.NodeList or Y.Node that should be used to modify class names
**/
getTarget : function() {
var node = this._node,
selector = node.getData( this.config.target ),
target;
if ( !selector ) {
selector = node.getAttribute('href');
selector = target && target.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
}
target = Y.all(selector);
if ( target.size() === 0 ) {
target = node.get('parentNode');
}
return target;
}
});
NS.Dropdown = DropdownPlugin;
NS.dropdown_delegation = function() {
Y.delegate('click', function(e) {
var target = e.currentTarget;
e.preventDefault();
if ( typeof e.target.dropdown === 'undefined' ) {
target.plug( DropdownPlugin );
target.dropdown.toggle();
}
}, document.body, '*[data-toggle=dropdown]' );
};
}, '@VERSION@' ,{requires:['plugin','event','event-outside']});
;
-274
View File
@@ -1,274 +0,0 @@
YUI.add('gallery-bootstrap-engine', function(Y) {
/**
* Bootstrap Engine for Plug and Play widgets. This class is meant to be used in
* conjuntion with the Injection Engine (gallery-bootstrap-engine). It facilitates the use of
* an iframe as a sandbox to execute certain tasks and/or a presention element.
*
* @module gallery-bootstrap-engine
* @requires node, base-base
* @class Y.BootstrapEngine
* @param config {Object} Configuration object
* @extends Y.Base
* @constructor
*/
///////////////////////////////////////////////////////////////////////////
//
// Private shorthands, constants and variables
//
///////////////////////////////////////////////////////////////////////////
var ATTR_HOST = 'host';
///////////////////////////////////////////////////////////////////////////
//
// Class definition
//
///////////////////////////////////////////////////////////////////////////
function BootstrapEngine () {
BootstrapEngine.superclass.constructor.apply(this, arguments);
}
Y.mix(BootstrapEngine, {
/**
* The identity of the class.
* @property BootstrapEngine.NAME
* @type string
* @static
* @final
* @readOnly
* @default 'bootstrap'
*/
NAME: 'bootstrap',
/**
* Static property used to define the default attribute configuration of
* the class.
* @property BootstrapEngine.ATTRS
* @type Object
* @protected
* @static
*/
ATTRS: {
/**
* @attribute container
* @type {Selector|Node}
* @writeOnce
* @description selector or node for the iframe's container. This is relative to the parent document.
*/
container: {
getter: function (v) {
var host = this.get(ATTR_HOST);
return host && host.one( v );
}
},
/**
* @attribute iframe
* @type {Node}
* @readyOnly
* @description Node reference to the iframe on the parent document.
*/
iframe: {
getter: function () {
var c = this.get('container');
return c && c.one('iframe' );
}
},
/**
* @attribute host
* @type {Object}
* @readyOnly
* @description A "Y" reference bound to the parent document.
*/
host: {
readyOnly: true
},
/**
* @attribute ready
* @type {Boolean}
* @readyOnly
* @description A "Y" reference bound to the parent document.
*/
ready: {
value: false,
readyOnly: true
}
}
});
Y.extend(BootstrapEngine, Y.Base, {
/**
* Any extra YUI module that you want to use by default in HOST YUI instance.
* "node" module will be added automatically since it's required by bootstrap.
* @property EXTRAS
* @type Array
* @default []
*/
EXTRAS: [],
/**
* Construction logic executed during Bootstrap Engine instantiation.
*
* @method initializer
* @param cfg {Object} Initial configuration
* @protected
*/
initializer: function () {
var instance = this,
parent, win, doc,
use = Y.Array(instance.EXTRAS),
host,
callBootFn = function () {
// finishing the initialization process async to facilitate
// addons to hook into _boot/_init/_bind/_ready if needed.
// todo: after migrating to 3.4 this is not longer needed, and we can use initializer and destroyer
// in each extension
Y.later(0, instance, function() {
instance._boot();
});
};
try {
parent = Y.config.win.parent;
win = parent && parent.window;
doc = win && win.document;
} catch(e) {
Y.log ('Parent window is not available or is a different domain', 'warn', 'bootstrap');
}
Y.log ('Initialization', 'info', 'bootstrap');
// parent is optional to facilitate testing and headless execution
if (parent && win && doc) {
host = YUI({
bootstrap: false,
win: win,
doc: doc
});
use.push('node', function() {
callBootFn();
});
// Creating a new YUI instance bound to the parent window
instance._set(ATTR_HOST, host.use.apply(host, use));
} else {
callBootFn();
}
},
/**
* Basic initialization routine, styling the iframe, binding events and
* connecting the bootstrap engine with the injection engine.
*
* @method _boot
* @protected
*/
_boot: function () {
var instance = this,
auto;
Y.log ('Boot', 'info', 'bootstrap');
// connecting with the injection engine before doing anything else
auto = instance._connect();
// adjust the iframe container in preparation for the first display action
instance._styleIframe();
// create some objects and markup
instance._init();
// binding some extra events
instance._bind();
// if the connect process wants to automatically execute the _ready, it should returns true.
if (auto) {
// connecting the bootstrap with the injection engine
instance._ready();
}
// marking the system as ready
instance._set('ready', true);
},
/**
* Connects the bootstrap with the injection engine running in the parent window. This method
* defines the hand-shake process between them. This method is meant to be called by
* the bootstrap engine _init method to start the connection.
*
* @method _connect
* @protected
*/
_connect: function () {
var guid = Y.config.guid, // injection engine guid value
host = this.get(ATTR_HOST),
pwin = host && host.config.win,
// getting a reference to the parent window callback function to notify
// to the injection engine that the bootstrap is ready
callback = guid && pwin && pwin.YUI && pwin.YUI.Env[guid];
Y.log ('Bootstrap connect', 'info', 'bootstrap');
// connecting bootstrap with the injection engines
return ( callback ? callback ( this ) : false );
},
/**
* Basic initialization routine, usually to create markup, new objects and attributes, etc.
* Overrides/Extends this prototype method to do your mojo.
*
* @method _init
* @protected
*/
_init: function () {
Y.log ('Init bootstrap', 'info', 'bootstrap');
},
/**
* Defines the binding logic for the bootstrap engine, listening for some attributes
* that might change, and defining the set of events that can be exposed to the injection engine.
* Overrides/Extends this prototype method to do your mojo.
*
* @method _bind
* @protected
*/
_bind: function () {
Y.log ('Binding bootstrap', 'info', 'bootstrap');
},
/**
* This method will be called only if the connect response with "true", you can use this
* to control the state of the initialization from the injection engine since it might
* take some time to load the stuff in the iframe, and the user might interact with the page
* invalidating the initialization routine.
* Overrides/Extends this prototype method to do your mojo.
*
* @method _ready
* @protected
*/
_ready : function () {
Y.log ('Bootstrap is ready', 'info', 'bootstrap');
},
/**
* The iframe that holds the bootstrap engine sometimes is used as a UI overlay.
* In this case, you can style it through this method. By default, it will set
* border, frameBorder, marginWidth, marginHeight, leftMargin and topMargin to
* cero, and allowTransparency to true.
*
* @method _styleIframe
* @protected
*/
_styleIframe: function () {
var iframe = this.get('iframe');
// making the iframe optional to facilitate tests
if (iframe) {
Y.log ('Styling the iframe', 'info', 'bootstrap');
Y.each (['border', 'marginWidth', 'marginHeight', 'leftMargin', 'topMargin'], function (name) {
iframe.setAttribute(name, 0);
});
}
}
});
Y.BootstrapEngine = BootstrapEngine;
}, '@VERSION@' ,{requires:['node','base-base']});
;
@@ -1,10 +0,0 @@
YUI().use('node', function(Y) {
var toggleShow = function(e) {
// Toggle the active class on both the clicked .btn-navbar and the .nav-collapse.
// Our CSS will set the height for these
var togglemenu = Y.one('.nav-collapse');
togglemenu.toggleClass('active');
this.toggleClass('active');
};
Y.delegate('click', toggleShow, Y.config.doc, '.btn-navbar');
});
+5 -27
View File
@@ -1,27 +1,5 @@
YUI().use('gallery-bootstrap');
YUI.add('gallery-bootstrap', function(Y) {
var NS = Y.namespace('Bootstrap');
NS.initializer = function(e) {
NS.dropdown_delegation();
NS.expandable_delegation();
};
NS.expandable_delegation = function() {
Y.delegate('click', function(e) {
e.preventDefault();
var target = e.currentTarget;
if ( ! target.collapse ) {
target.plug( Y.Bootstrap.Collapse );
}
target.collapse.toggle();
}, document.body, '*[data-toggle="collapse"]' );
};
Y.on('domready', NS.initializer);
}, '@VERSION@' ,{requires:[ 'gallery-bootstrap-dropdown', 'gallery-bootstrap-collapse', 'gallery-bootstrap-engine']});
;
// We need to actually use the code manually here as this is tricky do in
// themes at present.
YUI().use('moodle-theme_bootstrap-bootstrap', function(Y) {
Y.Moodle.theme_bootstrap.bootstrap.init();
});