kist-dochopper
Version:
Move elements on page depending on media query.
151 lines (116 loc) • 3.27 kB
JavaScript
var $ = require('jquery');
var smq = require('sort-media-queries');
var toarray = require('toarray');
var dom = require('./dom');
var events = require('./events');
var instance = require('./instance');
var meta = require('./meta');
var hopOnCondition = require('./hop-on-condition');
var emit = require('kist-toolbox/lib/event-emitter')(meta.name);
var jQuery = $;
/**
* @this {Dochopper}
*
* @param {String|Function|jQuery} into
*
* @return {jQuery}
*/
function getIntoElement ( into ) {
var el;
if ( typeof(into) === 'function' ) {
into = into.call(this.element, this.$el);
}
if ( typeof(into) === 'string' ) {
el = '[data-' + this.options.hopFromDataProp + '="' + into + '"]';
}
if ( into instanceof jQuery ) {
el = into;
}
return $(el);
}
/**
* Get conditions from DOM attribute
*
* @return {Array}
*/
function getDomConditions () {
var data = this.$el.data(this.options.hopConditionsDataProp);
return data ? toarray(data) : [];
}
function setConditions () {
this.conditions = this.conditions || [];
this.conditions = this.conditions.concat(getDomConditions.call(this), toarray(this.options.conditions));
this.conditions = smq(this.conditions, 'media');
$.each(this.conditions, $.proxy(function ( index, condition ) {
condition.get = {};
condition.get.media = window.matchMedia(condition.media);
condition.get.into = getIntoElement.call(this, condition.into);
condition.get.listener = $.proxy(hopOnCondition, this, condition.get.into, false);
}, this));
}
/**
* @class
*
* @param {Element} element
* @param {Object} options
*/
function Dochopper ( element, options ) {
this.element = element;
this.options = $.extend(true, {}, this.defaults, options);
this.queueActive = [];
this.queue = [];
instance.setup.call(this);
dom.setup.call(this);
setConditions.call(this);
events.setupInitial.call(this);
events.setupListeners.call(this);
}
$.extend(Dochopper.prototype, {
/**
* @param {jQuery} into
* @param {Object} media
*
* @return {}
*/
hop: function ( into, media ) {
this.$content.detach().appendTo(into);
if ( !this.queue.length ) {
emit(this, 'hop', [into, media]);
}
},
destroy: function () {
dom.destroy.call(this);
events.destroy.call(this);
instance.destroy.call(this);
},
rehop: function () {
var set = [];
$.each(this.conditions, $.proxy(function ( index, condition ) {
if ( condition.get.media.matches ) {
var el = getIntoElement.call(this, condition.into);
// Do this only if new element is not the same as the first cached element
if ( !condition.get.into.is(el) ) {
condition.get.into = el;
condition.get.media.removeListener(condition.get.listener);
condition.get.listener = $.proxy(hopOnCondition, this, condition.get.into, false);
condition.get.media.addListener(condition.get.listener);
set.push([condition.get.into, condition.get.media]);
}
}
}, this));
if ( set.length ) {
this.hop.apply(this, set[set.length - 1]);
}
},
defaults: {
conditions: [],
hop: $.noop,
hopFromDataProp: 'hop-from',
hopConditionsDataProp: 'hop-conditions',
classes: {
item: meta.ns.htmlClass + '-item',
isReady: 'is-ready'
}
}
});
module.exports = Dochopper;