From: Alexander Ebert Date: Fri, 8 Nov 2013 13:24:55 +0000 (+0100) Subject: Added enquire.js for better mobile support X-Git-Tag: 2.0.0_RC_1~9 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=1a65be7c34be907a86e6a99974cd8c6e9b1a9704;p=GitHub%2FWoltLab%2FWCF.git Added enquire.js for better mobile support --- diff --git a/wcfsetup/install/files/js/WCF.js b/wcfsetup/install/files/js/WCF.js index 2ad580d238..8616875502 100755 --- a/wcfsetup/install/files/js/WCF.js +++ b/wcfsetup/install/files/js/WCF.js @@ -82,6 +82,300 @@ // Inspired by base2 and Prototype (function(){var a=false,b=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend=function(c){function g(){if(!a&&this.init)this.init.apply(this,arguments);}var d=this.prototype;a=true;var e=new this;a=false;for(var f in c){e[f]=typeof c[f]=="function"&&typeof d[f]=="function"&&b.test(c[f])?function(a,b){return function(){var c=this._super;this._super=d[a];var e=b.apply(this,arguments);this._super=c;return e;};}(f,c[f]):c[f]}g.prototype=e;g.prototype.constructor=g;g.extend=arguments.callee;return g;};})(); +/*! + * enquire.js v2.1.0 - Awesome Media Queries in JavaScript + * Copyright (c) 2013 Nick Williams - http://wicky.nillia.ms/enquire.js + * License: MIT (http://www.opensource.org/licenses/mit-license.php) + */ + +;(function (name, context, factory) { + var matchMedia = context.matchMedia; + + if (typeof module !== 'undefined' && module.exports) { + module.exports = factory(matchMedia); + } + else if (typeof define === 'function' && define.amd) { + define(function() { + return (context[name] = factory(matchMedia)); + }); + } + else { + context[name] = factory(matchMedia); + } +}('enquire', this, function (matchMedia) { + + 'use strict'; + + /*jshint unused:false */ + /** + * Helper function for iterating over a collection + * + * @param collection + * @param fn + */ + function each(collection, fn) { + var i = 0, + length = collection.length, + cont; + + for(i; i < length; i++) { + cont = fn(collection[i], i); + if(cont === false) { + break; //allow early exit + } + } + } + + /** + * Helper function for determining whether target object is an array + * + * @param target the object under test + * @return {Boolean} true if array, false otherwise + */ + function isArray(target) { + return Object.prototype.toString.apply(target) === '[object Array]'; + } + + /** + * Helper function for determining whether target object is a function + * + * @param target the object under test + * @return {Boolean} true if function, false otherwise + */ + function isFunction(target) { + return typeof target === 'function'; + } + + /** + * Delegate to handle a media query being matched and unmatched. + * + * @param {object} options + * @param {function} options.match callback for when the media query is matched + * @param {function} [options.unmatch] callback for when the media query is unmatched + * @param {function} [options.setup] one-time callback triggered the first time a query is matched + * @param {boolean} [options.deferSetup=false] should the setup callback be run immediately, rather than first time query is matched? + * @constructor + */ + function QueryHandler(options) { + this.options = options; + !options.deferSetup && this.setup(); + } + QueryHandler.prototype = { + + /** + * coordinates setup of the handler + * + * @function + */ + setup : function() { + if(this.options.setup) { + this.options.setup(); + } + this.initialised = true; + }, + + /** + * coordinates setup and triggering of the handler + * + * @function + */ + on : function() { + !this.initialised && this.setup(); + this.options.match && this.options.match(); + }, + + /** + * coordinates the unmatch event for the handler + * + * @function + */ + off : function() { + this.options.unmatch && this.options.unmatch(); + }, + + /** + * called when a handler is to be destroyed. + * delegates to the destroy or unmatch callbacks, depending on availability. + * + * @function + */ + destroy : function() { + this.options.destroy ? this.options.destroy() : this.off(); + }, + + /** + * determines equality by reference. + * if object is supplied compare options, if function, compare match callback + * + * @function + * @param {object || function} [target] the target for comparison + */ + equals : function(target) { + return this.options === target || this.options.match === target; + } + + }; + /** + * Represents a single media query, manages it's state and registered handlers for this query + * + * @constructor + * @param {string} query the media query string + * @param {boolean} [isUnconditional=false] whether the media query should run regardless of whether the conditions are met. Primarily for helping older browsers deal with mobile-first design + */ + function MediaQuery(query, isUnconditional) { + this.query = query; + this.isUnconditional = isUnconditional; + this.handlers = []; + this.mql = matchMedia(query); + + var self = this; + this.listener = function(mql) { + self.mql = mql; + self.assess(); + }; + this.mql.addListener(this.listener); + } + MediaQuery.prototype = { + + /** + * add a handler for this query, triggering if already active + * + * @param {object} handler + * @param {function} handler.match callback for when query is activated + * @param {function} [handler.unmatch] callback for when query is deactivated + * @param {function} [handler.setup] callback for immediate execution when a query handler is registered + * @param {boolean} [handler.deferSetup=false] should the setup callback be deferred until the first time the handler is matched? + */ + addHandler : function(handler) { + var qh = new QueryHandler(handler); + this.handlers.push(qh); + + this.matches() && qh.on(); + }, + + /** + * removes the given handler from the collection, and calls it's destroy methods + * + * @param {object || function} handler the handler to remove + */ + removeHandler : function(handler) { + var handlers = this.handlers; + each(handlers, function(h, i) { + if(h.equals(handler)) { + h.destroy(); + return !handlers.splice(i,1); //remove from array and exit each early + } + }); + }, + + /** + * Determine whether the media query should be considered a match + * + * @return {Boolean} true if media query can be considered a match, false otherwise + */ + matches : function() { + return this.mql.matches || this.isUnconditional; + }, + + /** + * Clears all handlers and unbinds events + */ + clear : function() { + each(this.handlers, function(handler) { + handler.destroy(); + }); + this.mql.removeListener(this.listener); + this.handlers.length = 0; //clear array + }, + + /* + * Assesses the query, turning on all handlers if it matches, turning them off if it doesn't match + */ + assess : function() { + var action = this.matches() ? 'on' : 'off'; + + each(this.handlers, function(handler) { + handler[action](); + }); + } + }; + /** + * Allows for registration of query handlers. + * Manages the query handler's state and is responsible for wiring up browser events + * + * @constructor + */ + function MediaQueryDispatch () { + if(!matchMedia) { + throw new Error('matchMedia not present, legacy browsers require a polyfill'); + } + + this.queries = {}; + this.browserIsIncapable = !matchMedia('only all').matches; + } + + MediaQueryDispatch.prototype = { + + /** + * Registers a handler for the given media query + * + * @param {string} q the media query + * @param {object || Array || Function} options either a single query handler object, a function, or an array of query handlers + * @param {function} options.match fired when query matched + * @param {function} [options.unmatch] fired when a query is no longer matched + * @param {function} [options.setup] fired when handler first triggered + * @param {boolean} [options.deferSetup=false] whether setup should be run immediately or deferred until query is first matched + * @param {boolean} [shouldDegrade=false] whether this particular media query should always run on incapable browsers + */ + register : function(q, options, shouldDegrade) { + var queries = this.queries, + isUnconditional = shouldDegrade && this.browserIsIncapable; + + if(!queries[q]) { + queries[q] = new MediaQuery(q, isUnconditional); + } + + //normalise to object in an array + if(isFunction(options)) { + options = { match : options }; + } + if(!isArray(options)) { + options = [options]; + } + each(options, function(handler) { + queries[q].addHandler(handler); + }); + + return this; + }, + + /** + * unregisters a query and all it's handlers, or a specific handler for a query + * + * @param {string} q the media query to target + * @param {object || function} [handler] specific handler to unregister + */ + unregister : function(q, handler) { + var query = this.queries[q]; + + if(query) { + if(handler) { + query.removeHandler(handler); + } + else { + query.clear(); + delete this.queries[q]; + } + } + + return this; + } + }; + + return new MediaQueryDispatch(); + +})); + /** * Provides a hashCode() method for strings, similar to Java's String.hashCode(). *