UNPKG

formstone

Version:

Library of modular front end components.

326 lines (266 loc) 8.3 kB
/* global define */ (function(factory) { if (typeof define === "function" && define.amd) { define([ "jquery", "./core" ], factory); } else { factory(jQuery, Formstone); } }(function($, Formstone) { "use strict"; /** * @method private * @name initialize * @description Initializes plugin. * @param opts [object] "Plugin options" */ function initialize(options) { options = options || {}; // Build Media Queries for (var i in MQStrings) { if (MQStrings.hasOwnProperty(i)) { Defaults[i] = (options[i]) ? $.merge(options[i], Defaults[i]) : Defaults[i]; } } Defaults = $.extend(Defaults, options); // Sort Defaults.minWidth.sort(Functions.sortDesc); Defaults.maxWidth.sort(Functions.sortAsc); Defaults.minHeight.sort(Functions.sortDesc); Defaults.maxHeight.sort(Functions.sortAsc); // Bind Media Query Matches for (var j in MQStrings) { if (MQStrings.hasOwnProperty(j)) { MQMatches[j] = {}; for (var k in Defaults[j]) { if (Defaults[j].hasOwnProperty(k)) { var mq = window.matchMedia("(" + MQStrings[j] + ": " + (Defaults[j][k] === Infinity ? 100000 : Defaults[j][k]) + Defaults.unit + ")"); mq.addListener(onStateChange); MQMatches[j][Defaults[j][k]] = mq; } } } } // Initial Trigger onStateChange(); } /** * @method * @name bind * @description Binds callbacks to media query matching. * @param key [string] "Instance key" * @param media [string] "Media query to match" * @param data [object] "Object containing 'enter' and 'leave' callbacks" * @example $.mediaquery("bind", "key", "(min-width: 500px)", { ... }); */ function bind(key, media, data) { var mq = Window.matchMedia(media), mqKey = createKey(mq.media); if (!Bindings[mqKey]) { Bindings[mqKey] = { mq: mq, active: true, enter: {}, leave: {} }; Bindings[mqKey].mq.addListener(onBindingChange); } for (var i in data) { if (data.hasOwnProperty(i) && Bindings[mqKey].hasOwnProperty(i)) { Bindings[mqKey][i][key] = data[i]; } } var binding = Bindings[mqKey], matches = mq.matches; if (matches && binding[Events.enter].hasOwnProperty(key)) { binding[Events.enter][key].apply(mq); binding.active = true; } else if (!matches && binding[Events.leave].hasOwnProperty(key)) { binding[Events.leave][key].apply(mq); binding.active = false; } } /** * @method * @name unbind * @description Unbinds all callbacks from media query. * @param key [string] "Instance key" * @param media [string] "Media query to unbind; defaults to all" * @example $.mediaquery("unbind", "key"); */ function unbind(key, media) { if (!key) { return; } if (media) { // unbind specific query var mqKey = createKey(media); if (Bindings[mqKey]) { if (Bindings[mqKey].enter[key]) { delete Bindings[mqKey].enter[key]; } if (Bindings[mqKey].leave[key]) { delete Bindings[mqKey].leave[key]; } } } else { // unbind all for (var i in Bindings) { if (Bindings.hasOwnProperty(i)) { if (Bindings[i].enter[key]) { delete Bindings[i].enter[key]; } if (Bindings[i].leave[key]) { delete Bindings[i].leave[key]; } } } } } /** * @method private * @name setState * @description Sets current media query match state. */ function setState() { State = { unit: Defaults.unit }; for (var i in MQStrings) { if (MQStrings.hasOwnProperty(i)) { for (var j in MQMatches[i]) { if (MQMatches[i].hasOwnProperty(j)) { var state = (j === "Infinity") ? Infinity : parseInt(j, 10), isMax = i.indexOf("max") > -1; if (MQMatches[i][j].matches) { if (isMax) { if (!State[i] || state < State[i]) { State[i] = state; } } else { if (!State[i] || state > State[i]) { State[i] = state; } } } } } } } } /** * @method private * @name onStateChange * @description Handles media query changes. */ function onStateChange() { setState(); $Window.trigger(Events.mqChange, [State]); } /** * @method private * @name onBindingChange * @description Handles a binding's media query change. */ function onBindingChange(mq) { var mqkey = createKey(mq.media), binding = Bindings[mqkey], matches = mq.matches, event = matches ? Events.enter : Events.leave; if (binding && (binding.active || (!binding.active && matches))) { for (var i in binding[event]) { if (binding[event].hasOwnProperty(i)) { binding[event][i].apply(binding.mq); } } binding.active = true; } } /** * @method private * @name createKey * @description Creates valid object key from string. * @param text [String] "String to create key from" * @return [string] Valid object key */ function createKey(text) { return text.replace(/[^a-z0-9\s]/gi, '').replace(/[_\s]/g, '').replace(/^\s+|\s+$/g, ''); } /** * @method * @name state * @description Returns the current state. * @return [object] "Current state object" * @example var state = $.mediaquery("state"); */ /** * @method private * @name getState * @description Returns the current state. * @return [object] "Current state object" */ function getState() { return State; } /** * @plugin * @name Media Query * @description A jQuery plugin for responsive media query events. * @type utility * @main mediaquery.js * @dependency jQuery * @dependency core.js */ var Plugin = Formstone.Plugin("mediaquery", { utilities: { _initialize: initialize, state: getState, bind: bind, unbind: unbind }, /** * @events * @event mqchange.mediaquery "Change to a media query match; Triggered on window" */ events: { mqChange: "mqchange" } }), /** * @options * @param minWidth [array] <[ 0 ]> "Array of min-widths" * @param maxWidth [array] <[ Infinity ]> "Array of max-widths" * @param minHeight [array] <[ 0 ]> "Array of min-heights" * @param maxHeight [array] <[ Infinity ]> "Array of max-heights" * @param unit [string] <'px'> "Unit to use when matching widths and heights" */ Defaults = { minWidth: [0], maxWidth: [Infinity], minHeight: [0], maxHeight: [Infinity], unit: "px" }, // Raw events for switch Events = $.extend(Plugin.events, { enter: "enter", leave: "leave" }), // Localize References $Window = Formstone.$window, Window = $Window[0], Functions = Plugin.functions, // Internal State = null, Bindings = [], MQMatches = {}, MQStrings = { minWidth: "min-width", maxWidth: "max-width", minHeight: "min-height", maxHeight: "max-height" }; }) );