site/src/jquery.collapse.js
/*
* Collapse plugin for jQuery
* --
* source: http://github.com/danielstocks/jQuery-Collapse/
* site: http://webcloud.se/jQuery-Collapse
*
* @author Daniel Stocks (http://webcloud.se)
* Copyright 2013, Daniel Stocks
* Released under the MIT, BSD, and GPL Licenses.
*/
(function($) {
// Constructor
function Collapse (el, options) {
options = options || {};
var _this = this,
query = options.query || "> :even";
$.extend(_this, {
$el: el,
options : options,
sections: [],
isAccordion : options.accordion || false,
db : options.persist ? jQueryCollapseStorage(el[0].id) : false
});
// Figure out what sections are open if storage is used
_this.states = _this.db ? _this.db.read() : [];
// For every pair of elements in given
// element, create a section
_this.$el.find(query).each(function() {
var section = new Section($(this), _this);
_this.sections.push(section);
// Check current state of section
var state = _this.states[section._index()];
if(state === 0) {
section.$summary.removeClass("open");
}
if(state === 1) {
section.$summary.addClass("open");
}
// Show or hide accordingly
if(section.$summary.hasClass("open")) {
section.open(true);
}
else {
section.close(true);
}
});
// Capute ALL the clicks!
(function(scope) {
_this.$el.on("click", "[data-collapse-summary]",
$.proxy(_this.handleClick, scope));
}(_this));
}
Collapse.prototype = {
handleClick: function(e) {
e.preventDefault();
var sections = this.sections,
l = sections.length;
while(l--) {
if($.contains(sections[l].$summary[0], e.target)) {
sections[l].toggle();
break;
}
}
},
open : function(eq) {
if(isFinite(eq)) return this.sections[eq].open();
$.each(this.sections, function() {
this.open();
});
},
close: function(eq) {
if(isFinite(eq)) return this.sections[eq].close();
$.each(this.sections, function() {
this.close();
});
}
};
// Section constructor
function Section($el, parent) {
$.extend(this, {
isOpen : false,
$summary : $el
.attr("data-collapse-summary", "")
.wrapInner('<a href="#"/>'),
$details : $el.next(),
options: parent.options,
parent: parent
});
}
Section.prototype = {
toggle : function() {
if(this.isOpen) this.close();
else this.open();
},
close: function(bypass) {
this._changeState("close", bypass);
},
open: function(bypass) {
var _this = this;
if(_this.options.accordion && !bypass) {
$.each(_this.parent.sections, function() {
this.close();
});
}
_this._changeState("open", bypass);
},
_index: function() {
return $.inArray(this, this.parent.sections);
},
_changeState: function(state, bypass) {
var _this = this;
_this.isOpen = state == "open";
if($.isFunction(_this.options[state]) && !bypass) {
_this.options[state].apply(_this.$details);
} else {
if(_this.isOpen) _this.$details.show();
else _this.$details.hide();
}
_this.$summary.removeClass("open close").addClass(state);
_this.$details.attr("aria-hidden", state == "close");
_this.parent.$el.trigger(state, _this);
if(_this.parent.db) {
_this.parent.db.write(_this._index(), _this.isOpen);
}
}
};
// Expose in jQuery API
$.fn.extend({
collapse: function(options, scan) {
var nodes = (scan) ? $("body").find("[data-collapse]") : $(this);
return nodes.each(function() {
var settings = (scan) ? {} : options,
values = $(this).attr("data-collapse") || "";
$.each(values.split(" "), function(i,v) {
if(v) settings[v] = true;
});
new jQueryCollapse($(this), settings);
});
}
});
//jQuery DOM Ready
$(function() {
$.fn.collapse(false, true);
});
// Expose constructor to
// global namespace
jQueryCollapse = Collapse;
})(window.jQuery);