nm3clol-archived-russellcou.../russellcountyva.us/www.russellcountyva.us/Assets/Scripts/RWD/MediaFramework.js

737 lines
23 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

window.cpMedia = window.cpMedia || (function (global, documentElement) {
var DEBUG = false;
var matchMedia = global.matchMedia;
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
}
}
}
function isArray(target) {
return Object.prototype.toString.apply(target) === '[object Array]';
}
function isFunction(target) {
return typeof target === 'function';
}
function evalMediaQueryOnElement(query, element) {
var media = { all: true, screen: true, print: false };
var coordinates;
try {
coordinates = element.getBoundingClientRect();
} catch (e) {
coordinates = {
width: element.offsetWidth,
height: element.offsetHeight
};
}
media.thisWidth = coordinates.width || coordinates.right - coordinates.left;
media.thisHeight = coordinates.height || coordinates.bottom - coordinates.top;
media.thisAspectRatio = media.thisWidth / media.thisHeight,
media.thisOrientation = media.thisWidth > media.thisHeight ? "landscape" : "portrait";
var qReplaced = query
.replace(/\(|\)/g, "")
.replace(/\s*,\s*/g, ") || (")
.replace(/\s+and\s+/gi, " && ")
.replace(/min-(.*?):/gi, "$1>=")
.replace(/max-(.*?):/gi, "$1<=")
.replace(/above-(.*?):/gi, "$1>")
.replace(/below-(.*?):/gi, "$1<")
.replace(/min-|max-/gi, "")
.replace(/(all|screen|print)/, "d.$1")
.replace(/:/g, "==")
.replace(/([\w-]+)\s*([<>=]+)\s*(\w+)/g, function ($0, $1, $2, $3) {
return "d." + toCamelCase($1) + $2 + parseCSSNumber($3);
})
.replace(/([<>=]+)([A-z][\w-]*)/g, '$1"$2"');
var a = Function("d", "return(" + qReplaced + ")")(media);
return a;
}
function toCamelCase(value) {
return value.toLowerCase().replace(/-[a-z]/g, function ($0) {
return $0[1].toUpperCase();
});
}
function parseCSSNumber(value) {
return value.replace(/([\d\.]+)(%|em|in|pt|px)/, function ($0, $1, $2) {
return ($2 == "em") ? $1 * 16 : ($2 == "in") ? $1 * 96 : ($2 == "pt") ? $1 * 96 / 72 : ($2 == "%") ? $1 / (scope.innerWidth || documentElement.clientWidth) : $1;
});
}
function diag(message) {
if (DEBUG) {
console.log(message);
}
}
function QueryHandler(options, elements) {
this.options = options;
!options.deferSetup && this.setup(elements);
}
QueryHandler.prototype = {
setup: function (elements) {
if (this.options.setup) {
this.options.setup(elements);
}
this.initialised = true;
},
on: function (e, element) {
!this.initialised && this.setup();
this.options.match && this.options.match(e, element);
},
off: function (e, element) {
this.options.unmatch && this.options.unmatch(e, element);
},
destroy: function () {
this.options.destroy ? this.options.destroy() : this.off();
},
equals: function (target) {
return this.options === target || this.options.match === target;
}
};
function MediaQuery(query, isUnconditional) {
this.query = query;
this.isUnconditional = isUnconditional;
this.handlers = [];
this.mql = matchMedia(query);
if (this.mql.media != query) {
diag("Media query might be invalid=" + query + "\nParsed as=" + this.mql.media);
}
var self = this;
this.listener = function (mql) {
self.mql = mql;
self.assess();
};
this.mql.addListener(this.listener);
}
MediaQuery.prototype = {
addHandler: function (handler) {
var qh = new QueryHandler(handler);
this.handlers.push(qh);
this.matches() && qh.on();
},
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
}
});
},
matches: function () {
return this.mql.matches || this.isUnconditional;
},
clear: function () {
each(this.handlers, function (handler) {
handler.destroy();
});
this.mql.removeListener(this.listener);
this.handlers.length = 0; //clear array
},
assess: function () {
var action = this.matches() ? 'on' : 'off';
each(this.handlers, function (handler) {
handler[action]();
});
}
};
function ElementWrapper (element, query, rawQuery) {
this.element = element;
this.matched = false;
this.query = query;
this.rawQuery = rawQuery;
var rwdinfo = $(element).data('rwdinfo');
if (rwdinfo == null) {
rwdinfo = [];
}
rwdinfo.push(this);
$(element).data('rwdinfo', rwdinfo);
}
function MediaElement(query, isUnconditional) {
this.query = query;
this.isUnconditional = isUnconditional;
this.handlers = [];
this.isMediaElement = true;
this.elementWrappers = [];
this.initElements();
}
MediaElement.prototype = {
initElements : function () {
var all,
element,
match = this.query.match(/(.+?):media\((.+?)\)/);
this.elementWrappers = [];
if (match && /this/.test(match[2])) {
if (documentElement.querySelectorAll) {
all = documentElement.querySelectorAll(match[1]);
for (var index = 0; element = all[index]; ++index) {
this.elementWrappers.push(new ElementWrapper(element, match[2], this.query));
}
}
}
},
addHandler: function (handler) {
var elementWrappers = this.elementWrappers,
index,
elements = [];
for (index = 0; index < elementWrappers.length; ++index) {
elements.push(elementWrappers[index].element);
}
var qh = new QueryHandler(handler, elements);
this.handlers.push(qh);
this.assessOneHandler(null, qh);//this.matched && qh.on();
//this.assessForce(null, qh); //performance decrease, but not cached elements
},
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
}
});
},
clear: function () {
each(this.handlers, function (handler) {
handler.destroy();
});
//this.mql.removeListener(this.listener);
this.handlers.length = 0; //clear array
},
/// Access and execute specific handler if matches media query on current elements
assessOneHandler: function (e, handler) {
var elementWrappers = this.elementWrappers,
elementWrapper,
index;
for (index = 0; index < elementWrappers.length; ++index) {
elementWrapper = elementWrappers[index];
if (evalMediaQueryOnElement(elementWrapper.query, elementWrapper.element) || this.isUnconditional) {
handler.on(e, elementWrapper.element);
elementWrapper.matched = true;
}
}
},
/// Access and execute current handlers if matches or unmatched media query on current elements
assess: function (e) {
var elementWrappers = this.elementWrappers,
elementWrapper,
index;
for (index = 0; index < elementWrappers.length; ++index) {
elementWrapper = elementWrappers[index];
if (evalMediaQueryOnElement(elementWrapper.query, elementWrapper.element) || this.isUnconditional) {
this.match(e, elementWrapper);
} else {
this.unmatch(e, elementWrapper);
}
}
},
match: function (e, elementWrapper) {
if (elementWrapper.matched) {
return; //already on
}
each(this.handlers, function (handler) {
handler.on(e, elementWrapper.element);
});
elementWrapper.matched = true;
},
unmatch: function (e, elementWrapper) {
if (!elementWrapper.matched) {
return; //already off
}
each(this.handlers, function (handler) {
handler.off(e, elementWrapper.element);
});
elementWrapper.matched = false;
},
/// Access and execute current handlers if matches or unmatched media query on all elements (no cached)
/// If handler provided, access and execute only that handler if matches media query on all elements (no cached)
assessForce: function (e, handler) {
var all,
element,
match = this.query.match(/(.+?):media\((.+?)\)/);
if (match && /this/.test(match[2])) {
if (documentElement.querySelectorAll) {
all = documentElement.querySelectorAll(match[1]);
for (var index = 0; element = all[index]; ++index) {
var action = (evalMediaQueryOnElement(match[2], element) || this.isUnconditional) ? 'on' : 'off';
if (!handler) {
each(this.handlers, function (handler) {
handler[action](e, element);
});
} else if (action === 'on') {
handler[action](e, element);
}
}
}
}
}
};
function MediaQueryDispatch() {
if (!matchMedia) {
throw new Error('matchMedia not present, legacy browsers require a polyfill');
}
this.queries = {};
this.listening = false;
this.browserIsIncapable = !matchMedia('only all').matches;
this.fire = function (e) {
var queries = this.queries,
mediaQuery;
for (mediaQuery in queries) {
if (queries.hasOwnProperty(mediaQuery)) {
queries[mediaQuery].isMediaElement && queries[mediaQuery].assess(e);
//queries[mediaQuery].isMediaElement && queries[mediaQuery].assessForce(e, null); //performance decrease, but not cached elements
}
}
return this;
};
this.fireQuery = function (mediaQuery, e) {
var queries = this.queries;
if (queries.hasOwnProperty(mediaQuery)) {
queries[mediaQuery].isMediaElement && queries[mediaQuery].assess(e);
}
return this;
};
this.listen = function (timeout) {
var self = this;
timeout = timeout || 160;
//creates closure for separate timed events
function wireFire(event) {
var timer;
window.addEventListener(event, function (e) {
timer && clearTimeout(timer);
timer = setTimeout(function () {
self.fire(e);
}, timeout);
}, false);
}
//prevent multiple event handlers
if (this.listening) {
return this;
}
// any browser that doesn't implement this
// will not have media query support
if (window.addEventListener) {
wireFire('resize');
wireFire('orientationChange');
}
self.fire();
this.listening = true;
return this;
};
}
MediaQueryDispatch.prototype = {
register: function (q, options, shouldDegrade) {
var queries = this.queries,
isUnconditional = shouldDegrade && this.browserIsIncapable;
if (!queries[q]) {
if (/this/.test(q)) {
queries[q] = new MediaElement(q, isUnconditional);
this.listen();
} else {
queries[q] = new MediaQuery(q, isUnconditional);
}
}
//normalize 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;
},
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;
},
diag: function (message) {
diag(message);
}
};
return new MediaQueryDispatch();
}(this, document.documentElement));
function toggleClassMedia(className, mediaQueryElement, opts) {
//Extending toggleClass with options.
var defaults = {
match: null, // [function] code to execute when media query match on element
unmatch: null // [function] code to execute when media query unmatch on element
};
var options = $.extend(defaults, opts);
cpMedia.register(mediaQueryElement, {
setup: function (elements) {
elements = elements || [];
for (var i = 0; i < elements.length; i++) {
$(elements[i]).removeClass(className);
cpMedia.diag('$(element[' + i + ']).removeClass("' + className + '"), mediaQuery: ' + mediaQueryElement);
if (options.unmatch != null && typeof (options.unmatch) === 'function') {
options.unmatch(e, elements[i], className, null, mediaQueryElement);
cpMedia.diag('options.unmatch(e, element[' + i + '], "' + className + '", null, "' + mediaQueryElement + '")');
}
}
},
match: function (e, element) {
$(element).addClass(className);
cpMedia.diag('$(element).addClass("' + className + '"), mediaQuery: ' + mediaQueryElement);
if (options.match != null && typeof (options.match) === 'function') {
options.match(e, element, className, null, mediaQueryElement);
cpMedia.diag('options.match(e, element, "' + className + '", null, "' + mediaQueryElement + '")');
}
},
unmatch: function (e, element) {
$(element).removeClass(className);
cpMedia.diag('$(element).removeClass("' + className + '"), mediaQuery: ' + mediaQueryElement);
if (options.unmatch != null && typeof (options.unmatch) === 'function') {
options.unmatch(e, element, className, null, mediaQueryElement);
cpMedia.diag('options.unmatch(e, element, "' + className + '", null, "' + mediaQueryElement + '")');
}
}
}, false);
}
function toggleClassesMedia(classNameMatch, classNameUnmatch, mediaQueryElement, opts) {
//Extending toggleClass with options.
var defaults = {
match: null, // [function] code to execute when media query match on element
unmatch: null // [function] code to execute when media query unmatch on element
};
var options = $.extend(defaults, opts);
cpMedia.register(mediaQueryElement, {
setup: function (elements) {
elements = elements || [];
for (var i = 0; i < elements.length; i++) {
$(elements[i]).addClass(classNameUnmatch).removeClass(classNameMatch);
cpMedia.diag('$(elements[' + i + ']).removeClass("' + classNameMatch + '").addClass("' + classNameUnmatch + '"), mediaQuery: ' + mediaQueryElement);
if (options.unmatch != null && typeof (options.unmatch) === 'function') {
options.unmatch(null, elements[i], classNameMatch, classNameUnmatch, mediaQueryElement);
cpMedia.diag('options.unmatch(e, element, "' + classNameUnmatch + '", "' + classNameUnmatch + '", "' + mediaQueryElement + '")');
}
}
},
match: function (e, element) {
$(element).addClass(classNameMatch).removeClass(classNameUnmatch);
cpMedia.diag('$(element).addClass("' + classNameMatch + '").removeClass("' + classNameUnmatch + '"), mediaQuery: ' + mediaQueryElement);
if (options.match != null && typeof (options.match) === 'function') {
options.match(e, element, classNameMatch, classNameUnmatch, mediaQueryElement);
cpMedia.diag('options.match(e, element, "' + classNameMatch + '", "' + classNameUnmatch + '", "' + mediaQueryElement + '")');
}
},
unmatch: function (e, element) {
$(element).addClass(classNameUnmatch).removeClass(classNameMatch);
cpMedia.diag('$(element).removeClass("' + classNameMatch + '").addClass("' + classNameUnmatch + '"), mediaQuery: ' + mediaQueryElement);
if (options.unmatch != null && typeof (options.unmatch) === 'function') {
options.unmatch(e, element, classNameMatch, classNameUnmatch, mediaQueryElement);
cpMedia.diag('options.unmatch(e, element, "' + classNameUnmatch + '", "' + classNameUnmatch + '", " ' + mediaQueryElement + '")');
}
}
}, false);
}
function fireMediaElementQueriesOfChildren ($parent) {
var fireIndividualMediaQuery = function ($element) {
var rwdinfo = $element.data('rwdinfo');
for (var i = 0; i < rwdinfo.length; i++) {
window.cpMedia.fireQuery(rwdinfo[i].rawQuery);
}
};
$parent.find('*').hasData('rwdinfo').each(function () {
fireIndividualMediaQuery($(this));
});
if ($parent.hasData('rwdinfo').length == 1) {
fireIndividualMediaQuery($parent);
}
}
function fireAllMediaElementQueries() {
window.cpMedia.fire();
}
function matchMultiColumn(e, element, classNameMatch, classNameUnmatch, mediaQueryElement) {
$(element).find('div .row').addClass(classNameMatch);
if (classNameUnmatch != null)
$(element).find('div .row').removeClass(classNameUnmatch);
cpMedia.diag('$(' + element + ').find("div .row").addClass("' + classNameMatch + '"), mediaQuery: ' + mediaQueryElement);
}
function unmatchMultiColumn(e, element, classNameMatch, classNameUnmatch, mediaQueryElement) {
$(element).find('div .row').removeClass(classNameMatch);
if (classNameUnmatch != null)
$(element).find('div .row').addClass(classNameUnmatch);
cpMedia.diag('$(' + element + ').find("div .row").removeClass("' + classNameMatch + '"), mediaQuery: ' + mediaQueryElement);
}
function applyElementQueryToChildren ($parent) {
$parent.find("[data-elementquery]").each(function () {
var jsonQuery = $(this).data("elementquery");
if (jsonQuery != null && typeof(jsonQuery) === "object") {
var elementId = $(this).attr("id");
if (elementId == null || elementId == "") {
throw new Error("data-elementquery attribute can only by used on elements with unique id.");
}
if ($(this).parents('.megaMenu').length > 0 && !isResolvedOrState(window)) {
cpMedia.diag('#' + elementId + ' is inside megaMenu. MediaQuery: ' + $(this).attr("data-elementquery") + ' was not applied. Because the megaMenu has not been lazyLoaded');
return;
}
var options = {};
var matchFunction = $(this).data("elementquerymatch");
var unmatchFunction = $(this).data("elementqueryunmatch");
if (typeof matchFunction !== 'undefined' && matchFunction != '')
options.match = window[matchFunction];
if (typeof unmatchFunction !== 'undefined' && matchFunction != '')
options.unmatch = window[unmatchFunction];
for (var propertyName in jsonQuery) {
var mq = jsonQuery[propertyName];
mq = mq
.replace("max-", "this-max-")
.replace("min-", "this-min-")
.replace("below-", "this-below-")
.replace("above-", "this-above-");
var elementMediaQuery = "#" + elementId + ":media(" + mq + ")";
toggleClassMedia(propertyName, elementMediaQuery, options);
}
}
});
$parent.find("[data-elementqueryclasses]").each(function () {
var jsonQuery = $(this).data("elementqueryclasses");
if (jsonQuery != null && typeof (jsonQuery) === "object") {
var elementId = $(this).attr("id");
if (elementId == null || elementId == "") {
throw new Error("data-elementqueryclasses attribute can only by used on elements with unique id.");
}
if ($(this).parents('.megaMenu').length > 0 && !isResolvedOrState(window.Pages.megaMenuLoaded)) {
cpMedia.diag('#' + elementId + ' is inside megaMenu. MediaQuery: ' + $(this).attr("data-elementquery") + ' was not applied. Because the megaMenu has not been lazyLoaded');
return;
}
var options = {};
var matchFunction = $(this).data("elementquerymatch");
var unmatchFunction = $(this).data("elementqueryunmatch");
if (typeof matchFunction !== 'undefined' && matchFunction != '')
options.match = window[matchFunction];
if (typeof unmatchFunction !== 'undefined' && matchFunction != '')
options.unmatch = window[unmatchFunction];
for (var propertyName in jsonQuery) {
var mq = jsonQuery[propertyName];
mq = mq
.replace("max-", "this-max-")
.replace("min-", "this-min-")
.replace("below-", "this-below-")
.replace("above-", "this-above-");
var elementMediaQuery = "#" + elementId + ":media(" + mq + ")";
var propNameSplit = propertyName.split("-");
if (propNameSplit.length != 2)
throw new Error("data-elementqueryclasses attribute needs to have two classes separated by a dash (-)");
toggleClassesMedia(propNameSplit[0], propNameSplit[1], elementMediaQuery, options);
}
}
});
}
$(function () {
$("[data-contentcontainerbreakpoint]").each(function () {
var $container = $(this);
var breakpoint = $container.data("contentcontainerbreakpoint");
if (breakpoint != null && typeof(breakpoint) === "number") {
var elementId = $container.attr("id");
if (elementId == null || elementId == "") {
throw new Error("data-contentcontainerbreakpoint attribute can only by used on elements with unique id.");
}
var elementMediaQueryOuter = "#" + elementId + ":media(this-min-width:" + breakpoint + "em)";
cpMedia.diag('register: ' + elementMediaQueryOuter);
cpMedia.register(elementMediaQueryOuter, {
setup: function () {
$container.children('div.row.outer').removeClass('wide');
cpMedia.diag('#' + elementId + ' div.row.outer .removeClass("wide")');
},
match: function (e, element) {
$(element).children('div.row.outer').addClass('wide');
cpMedia.diag('#' + elementId + ' div.row.outer .addClass("wide")');
},
unmatch: function (e, element) {
$(element).children('div.row.outer').removeClass('wide');
cpMedia.diag('#' + elementId + ' div.row.outer .removeClass("wide")');
}
});
var innerBreakpoint = Math.round(breakpoint / 2);
var elementMediaQueryInner = "#" + elementId + ":media(this-min-width:" + innerBreakpoint + "em)";
cpMedia.diag('register: ' + elementMediaQueryInner);
cpMedia.register(elementMediaQueryInner, {
setup: function () {
$container.find('div.row.nest').removeClass('wide');
cpMedia.diag('#' + elementId + ' div.row.nest .removeClass("wide")');
},
match: function (e, element) {
$(element).find('div.row.nest').addClass('wide');
cpMedia.diag('#' + elementId + ' div.row.nest .addClass("wide")');
},
unmatch: function (e, element) {
$(element).find('div.row.nest').removeClass('wide');
cpMedia.diag('#' + elementId + ' div.row.nest .removeClass("wide")');
}
});
}
});
$("[data-ajaxinclude]").each(function () {
var jsonData = $(this).data("ajaxinclude");
if (jsonData != null && typeof (jsonData) === "object") {
var $div = $(this);
var elementId = $(this).attr("id");
if (elementId == null || elementId == "") {
throw new Error("data-ajaxinclude attribute can only by used on elements with unique id.");
}
var url = jsonData.url;
var query = jsonData.query;
cpMedia.register(query, {
setup: function () {
cpMedia.diag('div setup init');
AJAX(url, "GET", null, function (response) {
var $newContent = $(response);
/*$div.replaceWith($newContent); //1.) replace content with the div with ajax-include pattern
$div = $newContent;
$div.show();*/
$div.append($newContent); //2.) append content in the div with ajax-include pattern
console.log('div setup done');
}, false);
},
deferSetup: true,
match: function () {
$div.show();
cpMedia.diag('div show');
},
unmatch: function () {
$div.hide();
cpMedia.diag('div hide');
}
});
}
});
applyElementQueryToChildren($('body'));
//Setup execution of functions when resizing
window.Pages = window.Pages || {};
window.Pages.onResizeHandlers = window.Pages.onResizeHandlers || [];
if (!window.isRemoveSetHeights) {
window.Pages.onResizeHandlers.push(SetHeights);
}
if (typeof window.dynamicStretchContainers === 'function')
window.Pages.onResizeHandlers.push(window.dynamicStretchContainers);
if ($('#hdnWidgetManager').length == 0 && typeof rearrangeFlyoutsOnResizeEvents === 'function')
window.Pages.onResizeHandlers.push(rearrangeFlyoutsOnResizeEvents);
window.Pages.onResizeHandlersExecute = window.Pages.onResizeHandlersExecute || function () {
for (var i = 0; i < window.Pages.onResizeHandlers.length; i++) {
if (typeof (window.Pages.onResizeHandlers[i]) === 'function') {
window.Pages.onResizeHandlers[i]();
}
}
};
var timeout = 250; //time out to debounce execution of resize events
function executeOnResizeEvents(event) {
var timer;
window.addEventListener(event, function (e) {
timer && clearTimeout(timer);
timer = setTimeout(function () {
window.Pages.onResizeHandlersExecute();
}, timeout);
}, false);
}
executeOnResizeEvents('resize');
executeOnResizeEvents('orientationChange');
$.when(window.Pages.rwdReady.resolve()).done(function () {
window.Pages.rwdSetupComplete.resolve();
});
});