X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?p=src%2Fapp-framework-demo.git;a=blobdiff_plain;f=afb-client%2Fbower_components%2Ffoundation-apps%2Fdist%2Fjs%2Ffoundation-apps.js;fp=afb-client%2Fbower_components%2Ffoundation-apps%2Fdist%2Fjs%2Ffoundation-apps.js;h=1ad0c21423d79c8e557482fdf2184358c4c3ed4f;hp=0000000000000000000000000000000000000000;hb=5b1e6cc132f44262a873fa8296a2a3e1017b0278;hpb=f7d2f9ac4168ee5064580c666d508667a73cefc0 diff --git a/afb-client/bower_components/foundation-apps/dist/js/foundation-apps.js b/afb-client/bower_components/foundation-apps/dist/js/foundation-apps.js new file mode 100755 index 0000000..1ad0c21 --- /dev/null +++ b/afb-client/bower_components/foundation-apps/dist/js/foundation-apps.js @@ -0,0 +1,3136 @@ +/*! + * iconic.js v0.4.0 - The Iconic JavaScript library + * Copyright (c) 2014 Waybury - http://useiconic.com + */ + +!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.IconicJS=a():"undefined"!=typeof global?global.IconicJS=a():"undefined"!=typeof self&&(self.IconicJS=a())}(function(){var a;return function b(a,c,d){function e(g,h){if(!c[g]){if(!a[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};a[g][0].call(j.exports,function(b){var c=a[g][1][b];return e(c?c:b)},j,j.exports,b,a,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>>0;for(c=0;d>c;++c)c in this&&a.call(b,this[c],c,this)}),function(){if(Event.prototype.preventDefault||(Event.prototype.preventDefault=function(){this.returnValue=!1}),Event.prototype.stopPropagation||(Event.prototype.stopPropagation=function(){this.cancelBubble=!0}),!Element.prototype.addEventListener){var a=[],b=function(b,c){var d=this,e=function(a){a.target=a.srcElement,a.currentTarget=d,c.handleEvent?c.handleEvent(a):c.call(d,a)};if("DOMContentLoaded"==b){var f=function(a){"complete"==document.readyState&&e(a)};if(document.attachEvent("onreadystatechange",f),a.push({object:this,type:b,listener:c,wrapper:f}),"complete"==document.readyState){var g=new Event;g.srcElement=window,f(g)}}else this.attachEvent("on"+b,e),a.push({object:this,type:b,listener:c,wrapper:e})},c=function(b,c){for(var d=0;df?d.width:d.height;var g;g=32>b?"iconic-sm":b>=32&&128>b?"iconic-md":"iconic-lg";var h=a.getAttribute("class"),i=c.test(h)?h.replace(c,g):h+" "+g;a.setAttribute("class",i)}},h=function(){var a=document.querySelectorAll(".injected-svg.iconic-fluid");Array.prototype.forEach.call(a,function(a){g(a)})};document.addEventListener("DOMContentLoaded",function(){f()}),window.addEventListener("resize",function(){h()}),b.exports={refresh:g,refreshAll:h}},{}],8:[function(b,c,d){!function(b,e){"use strict";function f(a){a=a.split(" ");for(var b={},c=a.length,d=[];c--;)b.hasOwnProperty(a[c])||(b[a[c]]=1,d.unshift(a[c]));return d.join(" ")}var g="file:"===b.location.protocol,h=e.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"),i=Array.prototype.forEach||function(a,b){if(void 0===this||null===this||"function"!=typeof a)throw new TypeError;var c,d=this.length>>>0;for(c=0;d>c;++c)c in this&&a.call(b,this[c],c,this)},j={},k=0,l=[],m=[],n={},o=function(a){return a.cloneNode(!0)},p=function(a,b){m[a]=m[a]||[],m[a].push(b)},q=function(a){for(var b=0,c=m[a].length;c>b;b++)!function(b){setTimeout(function(){m[a][b](o(j[a]))},0)}(b)},r=function(a,c){if(void 0!==j[a])j[a]instanceof SVGSVGElement?c(o(j[a])):p(a,c);else{if(!b.XMLHttpRequest)return c("Browser does not support XMLHttpRequest"),!1;j[a]={},p(a,c);var d=new XMLHttpRequest;d.onreadystatechange=function(){if(4===d.readyState){if(404===d.status||null===d.responseXML)return c("Unable to load SVG file: "+a),g&&c("Note: SVG injection ajax calls do not work locally without adjusting security setting in your browser. Or consider using a local webserver."),c(),!1;if(!(200===d.status||g&&0===d.status))return c("There was a problem injecting the SVG: "+d.status+" "+d.statusText),!1;if(d.responseXML instanceof Document)j[a]=d.responseXML.documentElement;else if(DOMParser&&DOMParser instanceof Function){var b;try{var e=new DOMParser;b=e.parseFromString(d.responseText,"text/xml")}catch(f){b=void 0}if(!b||b.getElementsByTagName("parsererror").length)return c("Unable to parse SVG file: "+a),!1;j[a]=b.documentElement}q(a)}},d.open("GET",a),d.overrideMimeType&&d.overrideMimeType("text/xml"),d.send()}},s=function(a,c,d,e){var g=a.getAttribute("data-src")||a.getAttribute("src");if(!/svg$/i.test(g))return e("Attempted to inject a file with a non-svg extension: "+g),void 0;if(!h){var j=a.getAttribute("data-fallback")||a.getAttribute("data-png");return j?(a.setAttribute("src",j),e(null)):d?(a.setAttribute("src",d+"/"+g.split("/").pop().replace(".svg",".png")),e(null)):e("This browser does not support SVG and no PNG fallback was defined."),void 0}-1===l.indexOf(a)&&(l.push(a),a.setAttribute("src",""),r(g,function(d){if("undefined"==typeof d||"string"==typeof d)return e(d),!1;var h=a.getAttribute("id");h&&d.setAttribute("id",h);var j=a.getAttribute("title");j&&d.setAttribute("title",j);var m=[].concat(d.getAttribute("class")||[],"injected-svg",a.getAttribute("class")||[]).join(" ");d.setAttribute("class",f(m));var o=a.getAttribute("style");o&&d.setAttribute("style",o);var p=[].filter.call(a.attributes,function(a){return/^data-\w[\w\-]*$/.test(a.name)});i.call(p,function(a){a.name&&a.value&&d.setAttribute(a.name,a.value)});for(var q,r=d.querySelectorAll("defs clipPath[id]"),s=0,t=r.length;t>s;s++){q=r[s].id+"-"+k;for(var u=d.querySelectorAll('[clip-path*="'+r[s].id+'"]'),v=0,w=u.length;w>v;v++)u[v].setAttribute("clip-path","url(#"+q+")");r[s].id=q}d.removeAttribute("xmlns:a");for(var x,y,z=d.querySelectorAll("script"),A=[],B=0,C=z.length;C>B;B++)y=z[B].getAttribute("type"),y&&"application/ecmascript"!==y&&"application/javascript"!==y||(x=z[B].innerText||z[B].textContent,A.push(x),d.removeChild(z[B]));if(A.length>0&&("always"===c||"once"===c&&!n[g])){for(var D=0,E=A.length;E>D;D++)new Function(A[D])(b);n[g]=!0}a.parentNode.replaceChild(d,a),delete l[l.indexOf(a)],a=null,k++,e(d)}))},t=function(a,b,c){b=b||{};var d=b.evalScripts||"always",e=b.pngFallback||!1,f=b.each;if(void 0!==a.length){var g=0;i.call(a,function(b){s(b,d,e,function(b){f&&"function"==typeof f&&f(b),c&&a.length===++g&&c(g)})})}else a?s(a,d,e,function(b){f&&"function"==typeof f&&f(b),c&&c(1),a=null}):c&&c(0)};"object"==typeof c&&"object"==typeof c.exports?c.exports=d=t:"function"==typeof a&&a.amd?a(function(){return t}):"object"==typeof b&&(b.SVGInjector=t)}(window,document)},{}]},{},[1])(1)}); +(function() { + 'use strict'; + + angular.module('foundation.core.animation', []) + .service('FoundationAnimation', FoundationAnimation) + ; + + function FoundationAnimation() { + var animations = []; + var service = {}; + + var initClasses = ['ng-enter', 'ng-leave']; + var activeClasses = ['ng-enter-active', 'ng-leave-active']; + var activeGenericClass = 'is-active'; + var events = [ + 'webkitAnimationEnd', 'mozAnimationEnd', + 'MSAnimationEnd', 'oanimationend', + 'animationend', 'webkitTransitionEnd', + 'otransitionend', 'transitionend' + ]; + + service.animate = animate; + service.toggleAnimation = toggleAnimation; + + return service; + + function toggleAnimation(element, futureState) { + if(futureState) { + element.addClass(activeGenericClass); + } else { + element.removeClass(activeGenericClass); + } + } + + function animate(element, futureState, animationIn, animationOut) { + var timedOut = true; + var self = this; + self.cancelAnimation = cancelAnimation; + + var animationClass = futureState ? animationIn: animationOut; + var activation = futureState; + var initClass = activation ? initClasses[0] : initClasses[1]; + var activeClass = activation ? activeClasses[0] : activeClasses[1]; + //stop animation + registerElement(element); + reset(); + element.addClass(animationClass); + element.addClass(initClass); + + element.addClass(activeGenericClass); + + //force a "tick" + reflow(); + + //activate + element[0].style.transitionDuration = ''; + element.addClass(activeClass); + + element.one(events.join(' '), function() { + finishAnimation(); + }); + + setTimeout(function() { + if(timedOut) { + finishAnimation(); + } + }, 3000); + + function finishAnimation() { + deregisterElement(element); + reset(); //reset all classes + element[0].style.transitionDuration = ''; + element.removeClass(!activation ? activeGenericClass : ''); //if not active, remove active class + reflow(); + timedOut = false; + } + + + function cancelAnimation(element) { + deregisterElement(element); + angular.element(element).off(events.join(' ')); //kill all animation event handlers + timedOut = false; + } + + function registerElement(el) { + var elObj = { + el: el, + animation: self + }; + + //kill in progress animations + var inProgress = animations.filter(function(obj) { + return obj.el === el; + }); + if(inProgress.length > 0) { + var target = inProgress[0].el[0]; + + inProgress[0].animation.cancelAnimation(target); + } + + animations.push(elObj); + } + + function deregisterElement(el) { + var index; + var currentAnimation = animations.filter(function(obj, ind) { + if(obj.el === el) { + index = ind; + } + }); + + if(index >= 0) { + animations.splice(index, 1); + } + + } + + function reflow() { + return element[0].offsetWidth; + } + + function reset() { + element[0].style.transitionDuration = 0; + element.removeClass(initClasses.join(' ') + ' ' + activeClasses.join(' ') + ' ' + animationIn + ' ' + animationOut); + } + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.core', [ + 'foundation.core.animation' + ]) + .service('FoundationApi', FoundationApi) + .service('FoundationAdapter', FoundationAdapter) + .factory('Utils', Utils) + ; + + FoundationApi.$inject = ['FoundationAnimation']; + + function FoundationApi(FoundationAnimation) { + var listeners = {}; + var settings = {}; + var uniqueIds = []; + var service = {}; + + service.subscribe = subscribe; + service.unsubscribe = unsubscribe; + service.publish = publish; + service.getSettings = getSettings; + service.modifySettings = modifySettings; + service.generateUuid = generateUuid; + service.toggleAnimate = toggleAnimate; + service.closeActiveElements = closeActiveElements; + service.animate = animate; + + return service; + + function subscribe(name, callback) { + if (!listeners[name]) { + listeners[name] = []; + } + + listeners[name].push(callback); + return true; + } + + function unsubscribe(name, callback) { + if (listeners[name] !== undefined) { + delete listeners[name]; + } + if (typeof callback == 'function') { + callback.call(this); + } + } + + function publish(name, msg) { + if (!listeners[name]) { + listeners[name] = []; + } + + listeners[name].forEach(function(cb) { + cb(msg); + }); + + return; + } + + function getSettings() { + return settings; + } + + function modifySettings(tree) { + settings = angular.extend(settings, tree); + return settings; + } + + function generateUuid() { + var uuid = ''; + + //little trick to produce semi-random IDs + do { + uuid += 'zf-uuid-'; + for (var i=0; i<15; i++) { + uuid += Math.floor(Math.random()*16).toString(16); + } + } while(!uniqueIds.indexOf(uuid)); + + uniqueIds.push(uuid); + return uuid; + } + + function toggleAnimate(element, futureState) { + FoundationAnimation.toggleAnimate(element, futureState); + } + + function closeActiveElements(options) { + var self = this; + options = options || {}; + var activeElements = document.querySelectorAll('.is-active[zf-closable]'); + // action sheets are nested zf-closable elements, so we have to target the parent + var nestedActiveElements = document.querySelectorAll('[zf-closable] > .is-active') + + if (activeElements.length) { + angular.forEach(activeElements, function(el) { + if (options.exclude !== el.id) { + self.publish(el.id, 'close'); + } + }); + } + if (nestedActiveElements.length) { + angular.forEach(nestedActiveElements, function(el) { + var parentId = el.parentNode.id; + if (options.exclude !== parentId) { + self.publish(parentId, 'close'); + } + }) + } + } + + function animate(element, futureState, animationIn, animationOut) { + FoundationAnimation.animate(element, futureState, animationIn, animationOut); + } + } + + FoundationAdapter.$inject = ['FoundationApi']; + + function FoundationAdapter(foundationApi) { + + var service = {}; + + service.activate = activate; + service.deactivate = deactivate; + + return service; + + function activate(target) { + foundationApi.publish(target, 'show'); + } + + function deactivate(target) { + foundationApi.publish(target, 'hide'); + } + } + + + function Utils() { + var utils = {}; + + utils.throttle = throttleUtil; + + return utils; + + function throttleUtil(func, delay) { + var timer = null; + + return function () { + var context = this, args = arguments; + + if (timer === null) { + timer = setTimeout(function () { + func.apply(context, args); + timer = null; + }, delay); + } + }; + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.dynamicRouting.animations', ['foundation.dynamicRouting']) + .directive('uiView', uiView) + ; + + uiView.$inject = ['$rootScope', '$state']; + + function uiView($rootScope, $state) { + var directive = { + restrict : 'ECA', + priority : -400, + link : link + }; + + return directive; + + function link(scope, element) { + var animation = {}; + var animationEnded = false; + var presetHeight; + + var cleanup = [ + $rootScope.$on('$stateChangeStart', onStateChangeStart), + $rootScope.$on('$stateChangeError', onStateChangeError), + scope.$on('$stateChangeSuccess', onStateChangeSuccess), + scope.$on('$viewContentAnimationEnded', onViewContentAnimationEnded) + ]; + + var destroyed = scope.$on('$destroy', function onDestroy() { + angular.forEach(cleanup, function (cb) { + if (angular.isFunction(cb)) { + cb(); + } + }); + + destroyed(); + }); + + function onStateChangeStart(event, toState, toParams, fromState, fromParams) { + + if (fromState.animation) { + if (!fromState.animation.leave && !toState.animation.leave) { + return; + } + else { + animationRouter(event, toState, fromState); + } + } + } + + function animationRouter(event, toState, fromState) { + if (!animationEnded) { + resetParent(); + prepareParent(); + + element.removeClass(fromState.animation.leave); + } + else { + prepareParent(); + + element.addClass(fromState.animation.leave); + } + + } + + function onStateChangeError() { + if(animation.leave) { + element.removeClass(animation.leave); + } + + resetParent(); //reset parent if state change fails + } + + function onStateChangeSuccess() { + resetParent(); + if ($state.includes(getState()) && animation.enter) { + element.addClass(animation.enter); + } + } + + function onViewContentAnimationEnded(event) { + if (event.targetScope === scope && animation.enter) { + element.removeClass(animation.enter); + } + + animationEnded = true; + + } + + function getState() { + var view = element.data('$uiView'); + var state = view && view.state && view.state.self; + + if (state) { + angular.extend(animation, state.animation); + } + + return state; + } + + function resetParent() { + element.parent().removeClass('position-absolute'); + if(presetHeight !== true) { + element.parent()[0].style.height = null; + } + } + + function prepareParent() { + var parentHeight = parseInt(element.parent()[0].style.height); + var elHeight = parseInt(window.getComputedStyle(element[0], null).getPropertyValue('height')); + var tempHeight = parentHeight > 0 ? parentHeight : elHeight > 0 ? elHeight : ''; + + if(parentHeight > 0) { + presetHeight = true; + } + + element.parent()[0].style.height = tempHeight + 'px'; + element.parent().addClass('position-absolute'); + } + } + } + +})(); +(function() { + 'use strict'; + + angular.module('foundation.dynamicRouting', ['ui.router']) + .provider('$FoundationState', FoundationState) + .controller('DefaultController', DefaultController) + .config(DynamicRoutingConfig) + .run(DynamicRoutingRun) + ; + + FoundationState.$inject = ['$stateProvider']; + + function FoundationState($stateProvider) { + var complexViews = {}; + + this.registerDynamicRoutes = function(routes) { + var dynamicRoutes = routes || foundationRoutes; + + angular.forEach(dynamicRoutes, function(page) { + if (page.hasComposed) { + if (!angular.isDefined(complexViews[page.parent])) { + complexViews[page.parent] = { children: {} }; + } + + if (page.controller) { + page.controller = getController(page); + } + + complexViews[page.parent].children[page.name] = page; + + } else if (page.composed) { + if(!angular.isDefined(complexViews[page.name])) { + complexViews[page.name] = { children: {} }; + } + + if (page.controller) { + page.controller = getController(page); + } + + angular.extend(complexViews[page.name], page); + } else { + var state = { + url: page.url, + templateUrl: page.path, + abstract: page.abstract || false, + parent: page.parent || '', + controller: getController(page), + data: getData(page), + animation: buildAnimations(page), + }; + + $stateProvider.state(page.name, state); + } + }); + + angular.forEach(complexViews, function(page) { + var state = { + url: page.url, + parent: page.parent || '', + abstract: page.abstract || false, + data: getData(page), + animation: buildAnimations(page), + views: { + '': buildState(page.path, page) + } + }; + + angular.forEach(page.children, function(sub) { + state.views[sub.name + '@' + page.name] = buildState(sub.path, page); + }); + + $stateProvider.state(page.name, state); + }); + }; + + this.$get = angular.noop; + + function getData(page) { + var data = { vars: {} }; + if (page.data) { + if (typeof page.data.vars === "object") { + data.vars = page.data.vars; + } + delete page.data.vars; + angular.extend(data, page.data); + } + delete page.data; + angular.extend(data.vars, page); + return data; + } + + function buildState(path, state) { + return { + templateUrl: path, + controller: getController(state), + }; + } + + function getController(state) { + var ctrl = state.controller || 'DefaultController'; + + if (!/\w\s+as\s+\w/.test(ctrl)) { + ctrl += ' as PageCtrl'; + } + + return ctrl; + } + + function buildAnimations(state) { + var animations = {}; + + if (state.animationIn) { + animations.enter = state.animationIn; + } + + if (state.animationOut) { + animations.leave = state.animationOut; + } + + return animations; + } + } + + DefaultController.$inject = ['$scope', '$stateParams', '$state']; + + function DefaultController($scope, $stateParams, $state) { + var params = {}; + angular.forEach($stateParams, function(value, key) { + params[key] = value; + }); + + $scope.params = params; + $scope.current = $state.current.name; + + if($state.current.views) { + $scope.vars = $state.current.data.vars; + $scope.composed = $state.current.data.vars.children; + } else { + $scope.vars = $state.current.data.vars; + } + } + + DynamicRoutingConfig.$inject = ['$FoundationStateProvider']; + + function DynamicRoutingConfig(FoundationStateProvider) { + FoundationStateProvider.registerDynamicRoutes(foundationRoutes); + } + + DynamicRoutingRun.$inject = ['$rootScope', '$state', '$stateParams']; + + function DynamicRoutingRun($rootScope, $state, $stateParams) { + $rootScope.$state = $state; + $rootScope.$stateParams = $stateParams; + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.mediaquery', ['foundation.core']) + .run(mqInitRun) + .factory('FoundationMQInit', FoundationMQInit) + .factory('mqHelpers', mqHelpers) + .service('FoundationMQ', FoundationMQ) + ; + + mqInitRun.$inject = ['FoundationMQInit']; + + function mqInitRun(mqInit) { + mqInit.init(); + } + + FoundationMQInit.$inject = ['mqHelpers', 'FoundationApi', 'Utils']; + + function FoundationMQInit(helpers, foundationApi, u){ + var factory = {}; + var namedQueries = { + 'default' : 'only screen', + landscape : 'only screen and (orientation: landscape)', + portrait : 'only screen and (orientation: portrait)', + retina : 'only screen and (-webkit-min-device-pixel-ratio: 2),' + + 'only screen and (min--moz-device-pixel-ratio: 2),' + + 'only screen and (-o-min-device-pixel-ratio: 2/1),' + + 'only screen and (min-device-pixel-ratio: 2),' + + 'only screen and (min-resolution: 192dpi),' + + 'only screen and (min-resolution: 2dppx)' + }; + + factory.init = init; + + return factory; + + function init() { + var mediaQueries; + var extractedMedia; + var mediaObject; + + helpers.headerHelper(['foundation-mq']); + extractedMedia = helpers.getStyle('.foundation-mq', 'font-family'); + + mediaQueries = helpers.parseStyleToObject((extractedMedia)); + + for(var key in mediaQueries) { + mediaQueries[key] = 'only screen and (min-width: ' + mediaQueries[key].replace('rem', 'em') + ')'; + } + + + foundationApi.modifySettings({ + mediaQueries: angular.extend(mediaQueries, namedQueries) + }); + + window.addEventListener('resize', u.throttle(function() { + foundationApi.publish('resize', 'window resized'); + }, 50)); + + } + } + + + function mqHelpers() { + var factory = {}; + + factory.headerHelper = headerHelper; + factory.getStyle = getStyle; + factory.parseStyleToObject = parseStyleToObject; + + return factory; + + function headerHelper(classArray) { + var i = classArray.length; + var head = angular.element(document.querySelectorAll('head')); + + while(i--) { + head.append(''); + } + + return; + } + + function getStyle(selector, styleName) { + var elem = document.querySelectorAll(selector)[0]; + var style = window.getComputedStyle(elem, null); + + return style.getPropertyValue('font-family'); + } + + // https://github.com/sindresorhus/query-string + function parseStyleToObject(str) { + var styleObject = {}; + + if (typeof str !== 'string') { + return styleObject; + } + + str = str.trim().slice(1, -1); // browsers re-quote string style values + + if (!str) { + return styleObject; + } + + styleObject = str.split('&').reduce(function(ret, param) { + var parts = param.replace(/\+/g, ' ').split('='); + var key = parts[0]; + var val = parts[1]; + key = decodeURIComponent(key); + + // missing `=` should be `null`: + // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters + val = val === undefined ? null : decodeURIComponent(val); + + if (!ret.hasOwnProperty(key)) { + ret[key] = val; + } else if (Array.isArray(ret[key])) { + ret[key].push(val); + } else { + ret[key] = [ret[key], val]; + } + return ret; + }, {}); + + return styleObject; + } + } + + FoundationMQ.$inject = ['FoundationApi']; + + function FoundationMQ(foundationApi) { + var service = []; + + service.getMediaQueries = getMediaQueries; + service.match = match; + service.collectScenariosFromElement = collectScenariosFromElement; + + return service; + + function getMediaQueries() { + return foundationApi.getSettings().mediaQueries; + } + + function match(scenarios) { + var count = scenarios.length; + var queries = service.getMediaQueries(); + var matches = []; + + if (count > 0) { + while (count--) { + var mq; + var rule = scenarios[count].media; + + if (queries[rule]) { + mq = matchMedia(queries[rule]); + } else { + mq = matchMedia(rule); + } + + if (mq.matches) { + matches.push({ ind: count}); + } + } + } + + return matches; + } + + // Collects a scenario object and templates from element + function collectScenariosFromElement(parentElement) { + var scenarios = []; + var templates = []; + + var elements = parentElement.children(); + var i = 0; + + angular.forEach(elements, function(el) { + var elem = angular.element(el); + + + //if no source or no html, capture element itself + if (!elem.attr('src') || !elem.attr('src').match(/.html$/)) { + templates[i] = elem; + scenarios[i] = { media: elem.attr('media'), templ: i }; + } else { + scenarios[i] = { media: elem.attr('media'), src: elem.attr('src') }; + } + + i++; + }); + + return { + scenarios: scenarios, + templates: templates + }; + } + } +})(); + +angular.module('markdown', []) + .directive('markdown', function() { + return { + restrict: 'A', + link: function(scope, element, attrs, controller) { + element.html(marked(element.html())); + } + }; + +}); + +'use strict'; + +(function(){ + var svgDirectives = {}; + + angular.forEach([ + 'clipPath', + 'colorProfile', + 'src', + 'cursor', + 'fill', + 'filter', + 'marker', + 'markerStart', + 'markerMid', + 'markerEnd', + 'mask', + 'stroke' + ], + function(attr) { + svgDirectives[attr] = [ + '$rootScope', + '$location', + '$interpolate', + '$sniffer', + 'urlResolve', + 'computeSVGAttrValue', + 'svgAttrExpressions', + function( + $rootScope, + $location, + $interpolate, + $sniffer, + urlResolve, + computeSVGAttrValue, + svgAttrExpressions) { + return { + restrict: 'A', + link: function(scope, element, attrs) { + var initialUrl; + + //Only apply to svg elements to avoid unnecessary observing + //Check that is in html5Mode and that history is supported + if ((!svgAttrExpressions.SVG_ELEMENT.test(element[0] && + element[0].toString())) || + !$location.$$html5 || + !$sniffer.history) return; + + //Assumes no expressions, since svg is unforgiving of xml violations + initialUrl = attrs[attr]; + attrs.$observe(attr, updateValue); + $rootScope.$on('$locationChangeSuccess', updateValue); + + function updateValue () { + var newVal = computeSVGAttrValue(initialUrl); + //Prevent recursive updating + if (newVal && attrs[attr] !== newVal) attrs.$set(attr, newVal); + } + } + }; + }]; + }); + + angular.module('ngSVGAttributes', []). + factory('urlResolve', [function() { + //Duplicate of urlResolve & urlParsingNode in angular core + var urlParsingNode = document.createElement('a'); + return function urlResolve(url) { + urlParsingNode.setAttribute('href', url); + return urlParsingNode; + }; + }]). + value('svgAttrExpressions', { + FUNC_URI: /^url\((.*)\)$/, + SVG_ELEMENT: /SVG[a-zA-Z]*Element/, + HASH_PART: /#.*/ + }). + factory('computeSVGAttrValue', [ + '$location', '$sniffer', 'svgAttrExpressions', 'urlResolve', + function($location, $sniffer, svgAttrExpressions, urlResolve) { + return function computeSVGAttrValue(url) { + var match, fullUrl; + if (match = svgAttrExpressions.FUNC_URI.exec(url)) { + //hash in html5Mode, forces to be relative to current url instead of base + if (match[1].indexOf('#') === 0) { + fullUrl = $location.absUrl(). + replace(svgAttrExpressions.HASH_PART, '') + + match[1]; + } + //Presumably links to external SVG document + else { + fullUrl = urlResolve(match[1]); + } + } + return fullUrl ? 'url(' + fullUrl + ')' : null; + }; + } + ] + ). + directive(svgDirectives); +}()); + +(function() { + 'use strict'; + + angular.module('foundation.accordion', []) + .controller('ZfAccordionController', zfAccordionController) + .directive('zfAccordion', zfAccordion) + .directive('zfAccordionItem', zfAccordionItem) + ; + + zfAccordionController.$inject = ['$scope']; + + function zfAccordionController($scope) { + var controller = this; + var sections = controller.sections = $scope.sections = []; + var multiOpen = controller.multiOpen = $scope.multiOpen = $scope.multiOpen || false; + var collapsible = controller.collapsible = $scope.collapsible = $scope.multiOpen || $scope.collapsible || true; //multi open infers a collapsible true + var autoOpen = controller.autoOpen = $scope.autoOpen = $scope.autoOpen || true; //auto open opens first tab on render + + controller.select = function(selectSection) { + sections.forEach(function(section) { + //if multi open is allowed, toggle a tab + if(controller.multiOpen) { + if(section.scope === selectSection) { + section.scope.active = !section.scope.active; + } + } else { + //non multi open will close all tabs and open one + if(section.scope === selectSection) { + //if collapsible is allowed, a tab will toggle + section.scope.active = collapsible ? !section.scope.active : true; + } else { + section.scope.active = false; + } + } + + }); + }; + + controller.addSection = function addsection(sectionScope) { + sections.push({ scope: sectionScope }); + + if(sections.length === 1 && autoOpen === true) { + sections[0].active = true; + sections[0].scope.active = true; + } + }; + + controller.closeAll = function() { + sections.forEach(function(section) { + section.scope.active = false; + }); + }; + } + + function zfAccordion() { + var directive = { + restrict: 'EA', + transclude: 'true', + replace: true, + templateUrl: 'components/accordion/accordion.html', + controller: 'ZfAccordionController', + scope: { + multiOpen: '@?', + collapsible: '@?', + autoOpen: '@?' + }, + link: link + }; + + return directive; + + function link(scope, element, attrs, controller) { + scope.multiOpen = controller.multiOpen = scope.multiOpen === "true" ? true : false; + scope.collapsible = controller.collapsible = scope.collapsible === "true" ? true : false; + scope.autoOpen = controller.autoOpen = scope.autoOpen === "true" ? true : false; + } + } + + //accordion item + function zfAccordionItem() { + var directive = { + restrict: 'EA', + templateUrl: 'components/accordion/accordion-item.html', + transclude: true, + scope: { + title: '@' + }, + require: '^zfAccordion', + replace: true, + controller: function() {}, + link: link + }; + + return directive; + + function link(scope, element, attrs, controller, transclude) { + scope.active = false; + controller.addSection(scope); + + scope.activate = function() { + controller.select(scope); + }; + + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.actionsheet', ['foundation.core']) + .controller('ZfActionSheetController', zfActionSheetController) + .directive('zfActionSheet', zfActionSheet) + .directive('zfAsContent', zfAsContent) + .directive('zfAsButton', zfAsButton) + .service('FoundationActionSheet', FoundationActionSheet) + ; + + FoundationActionSheet.$inject = ['FoundationApi']; + + function FoundationActionSheet(foundationApi) { + var service = {}; + + service.activate = activate; + service.deactivate = deactivate; + + return service; + + //target should be element ID + function activate(target) { + foundationApi.publish(target, 'show'); + } + + //target should be element ID + function deactivate(target) { + foundationApi.publish(target, 'hide'); + } + } + + zfActionSheetController.$inject = ['$scope', 'FoundationApi']; + + function zfActionSheetController($scope, foundationApi) { + var controller = this; + var content = controller.content = $scope.content; + var container = controller.container = $scope.container; + var body = angular.element(document.body); + + controller.registerContent = function(scope) { + content = scope; + content.active = false; + }; + + controller.registerContainer = function(scope) { + container = scope; + container.active = false; + }; + + controller.toggle = toggle; + controller.hide = hide; + + controller.registerListener = function() { + document.body.addEventListener('click', listenerLogic); + }; + + controller.deregisterListener = function() { + document.body.removeEventListener('click', listenerLogic); + } + + function listenerLogic(e) { + var el = e.target; + var insideActionSheet = false; + + do { + if(el.classList && el.classList.contains('action-sheet-container')) { + insideActionSheet = true; + break; + } + + } while ((el = el.parentNode)); + + if(!insideActionSheet) { + // if the element has a toggle attribute, do nothing + if (e.target.attributes['zf-toggle'] || e.target.attributes['zf-hard-toggle']) { + return; + }; + // if the element is outside the action sheet and is NOT a toggle element, hide + hide(); + } + } + + function hide() { + content.hide(); + container.hide(); + + content.$apply(); + container.$apply(); + } + + function toggle() { + content.toggle(); + container.toggle(); + + content.$apply(); + container.$apply(); + } + } + + zfActionSheet.$inject = ['FoundationApi']; + + function zfActionSheet(foundationApi) { + var directive = { + restrict: 'EA', + transclude: true, + replace: true, + templateUrl: 'components/actionsheet/actionsheet.html', + controller: 'ZfActionSheetController', + compile: compile + }; + + return directive; + + function compile() { + + return { + pre: preLink, + post: postLink + }; + + function preLink(scope, iElement, iAttrs) { + iAttrs.$set('zf-closable', 'actionsheet'); + } + + function postLink(scope, element, attrs, controller) { + var id = attrs.id || foundationApi.generateUuid(); + attrs.$set('id', id); + + scope.active = false; + + foundationApi.subscribe(id, function(msg) { + if (msg === 'toggle') { + controller.toggle(); + } + + if (msg === 'hide' || msg === 'close') { + controller.hide(); + } + + }); + + controller.registerContainer(scope); + + scope.toggle = function() { + scope.active = !scope.active; + return; + }; + + scope.hide = function() { + scope.active = false; + return; + }; + } + } + } + + zfAsContent.$inject = ['FoundationApi']; + + function zfAsContent(foundationApi) { + var directive = { + restrict: 'EA', + transclude: true, + replace: true, + templateUrl: 'components/actionsheet/actionsheet-content.html', + require: '^zfActionSheet', + scope: { + position: '@?' + }, + link: link + }; + + return directive; + + function link(scope, element, attrs, controller) { + scope.active = false; + scope.position = scope.position || 'bottom'; + controller.registerContent(scope); + + scope.toggle = function() { + scope.active = !scope.active; + if(scope.active) { + controller.registerListener(); + } else { + controller.deregisterListener(); + } + + return; + }; + + scope.hide = function() { + scope.active = false; + controller.deregisterListener(); + return; + }; + } + } + + zfAsButton.$inject = ['FoundationApi']; + + function zfAsButton(foundationApi) { + var directive = { + restrict: 'EA', + transclude: true, + replace: true, + templateUrl: 'components/actionsheet/actionsheet-button.html', + require: '^zfActionSheet', + scope: { + title: '@?' + }, + link: link + } + + return directive; + + function link(scope, element, attrs, controller) { + + element.on('click', function(e) { + controller.toggle(); + e.preventDefault(); + }); + + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.common', ['foundation.core']) + .directive('zfClose', zfClose) + .directive('zfOpen', zfOpen) + .directive('zfToggle', zfToggle) + .directive('zfEscClose', zfEscClose) + .directive('zfSwipeClose', zfSwipeClose) + .directive('zfHardToggle', zfHardToggle) + ; + + zfClose.$inject = ['FoundationApi']; + + function zfClose(foundationApi) { + var directive = { + restrict: 'A', + link: link + }; + + return directive; + + function link(scope, element, attrs) { + var targetId = ''; + if (attrs.zfClose) { + targetId = attrs.zfClose; + } else { + var parentElement= false; + var tempElement = element.parent(); + //find parent modal + while(parentElement === false) { + if(tempElement[0].nodeName == 'BODY') { + parentElement = ''; + } + + if(typeof tempElement.attr('zf-closable') !== 'undefined' && tempElement.attr('zf-closable') !== false) { + parentElement = tempElement; + } + + tempElement = tempElement.parent(); + } + targetId = parentElement.attr('id'); + } + + element.on('click', function(e) { + foundationApi.publish(targetId, 'close'); + e.preventDefault(); + }); + } + } + + zfOpen.$inject = ['FoundationApi']; + + function zfOpen(foundationApi) { + var directive = { + restrict: 'A', + link: link + }; + + return directive; + + function link(scope, element, attrs) { + element.on('click', function(e) { + foundationApi.publish(attrs.zfOpen, 'open'); + e.preventDefault(); + }); + } + } + + zfToggle.$inject = ['FoundationApi']; + + function zfToggle(foundationApi) { + var directive = { + restrict: 'A', + link: link + } + + return directive; + + function link(scope, element, attrs) { + element.on('click', function(e) { + foundationApi.publish(attrs.zfToggle, 'toggle'); + e.preventDefault(); + }); + } + } + + zfEscClose.$inject = ['FoundationApi']; + + function zfEscClose(foundationApi) { + var directive = { + restrict: 'A', + link: link + }; + + return directive; + + function link(scope, element, attrs) { + element.on('keyup', function(e) { + if (e.keyCode === 27) { + foundationApi.closeActiveElements(); + } + e.preventDefault(); + }); + } + } + + zfSwipeClose.$inject = ['FoundationApi']; + + function zfSwipeClose(foundationApi) { + var directive = { + restrict: 'A', + link: link + }; + return directive; + + function link($scope, element, attrs) { + var swipeDirection; + var hammerElem; + if (Hammer) { + hammerElem = new Hammer(element[0]); + // set the options for swipe (to make them a bit more forgiving in detection) + hammerElem.get('swipe').set({ + direction: Hammer.DIRECTION_ALL, + threshold: 5, // this is how far the swipe has to travel + velocity: 0.5 // and this is how fast the swipe must travel + }); + } + // detect what direction the directive is pointing + switch (attrs.zfSwipeClose) { + case 'right': + swipeDirection = 'swiperight'; + break; + case 'left': + swipeDirection = 'swipeleft'; + break; + case 'up': + swipeDirection = 'swipeup'; + break; + case 'down': + swipeDirection = 'swipedown'; + break; + default: + swipeDirection = 'swipe'; + } + hammerElem.on(swipeDirection, function() { + foundationApi.publish(attrs.id, 'close'); + }); + } + } + + zfHardToggle.$inject = ['FoundationApi']; + + function zfHardToggle(foundationApi) { + var directive = { + restrict: 'A', + link: link + }; + + return directive; + + function link(scope, element, attrs) { + element.on('click', function(e) { + foundationApi.closeActiveElements({exclude: attrs.zfHardToggle}); + foundationApi.publish(attrs.zfHardToggle, 'toggle'); + e.preventDefault(); + }); + } + } + +})(); + +(function () { + 'use strict'; + + angular.module('foundation.iconic', []) + .provider('Iconic', Iconic) + .directive('zfIconic', zfIconic) + ; + + // iconic wrapper + function Iconic() { + // default path + var assetPath = 'assets/img/iconic/'; + + /** + * Sets the path used to locate the iconic SVG files + * @param {string} path - the base path used to locate the iconic SVG files + */ + this.setAssetPath = function (path) { + assetPath = angular.isString(path) ? path : assetPath; + }; + + /** + * Service implementation + * @returns {{}} + */ + this.$get = function () { + var iconicObject = new IconicJS(); + + var service = { + getAccess: getAccess, + getAssetPath: getAssetPath + }; + + return service; + + /** + * + * @returns {Window.IconicJS} + */ + function getAccess() { + return iconicObject; + } + + /** + * + * @returns {string} + */ + function getAssetPath() { + return assetPath; + } + }; + } + + zfIconic.$inject = ['Iconic', 'FoundationApi', '$compile']; + + function zfIconic(iconic, foundationApi, $compile) { + var directive = { + restrict: 'A', + template: '', + transclude: true, + replace: true, + scope: { + dynSrc: '=?', + dynIcon: '=?', + size: '@?', + icon: '@', + iconDir: '@?' + }, + compile: compile + }; + + return directive; + + function compile() { + var contents, assetPath; + + return { + pre: preLink, + post: postLink + }; + + function preLink(scope, element, attrs) { + + if (scope.iconDir) { + // path set via attribute + assetPath = scope.iconDir; + } else { + // default path + assetPath = iconic.getAssetPath(); + } + // make sure ends with / + if (assetPath.charAt(assetPath.length - 1) !== '/') { + assetPath += '/'; + } + + if (scope.dynSrc) { + attrs.$set('data-src', scope.dynSrc); + } else if (scope.dynIcon) { + attrs.$set('data-src', assetPath + scope.dynIcon + '.svg'); + } else { + if (scope.icon) { + attrs.$set('data-src', assetPath + scope.icon + '.svg'); + } else { + // To support expressions on data-src + attrs.$set('data-src', attrs.src); + } + } + + // check if size already added as class + if (!element.hasClass('iconic-sm') && !element.hasClass('iconic-md') && !element.hasClass('iconic-lg')) { + var iconicClass; + switch (scope.size) { + case 'small': + iconicClass = 'iconic-sm'; + break; + case 'medium': + iconicClass = 'iconic-md'; + break; + case 'large': + iconicClass = 'iconic-lg'; + break; + default: + iconicClass = 'iconic-fluid'; + } + element.addClass(iconicClass); + } + + // save contents of un-inject html, to use for dynamic re-injection + contents = element[0].outerHTML; + } + + function postLink(scope, element, attrs) { + var svgElement, ico = iconic.getAccess(); + + injectSvg(element[0]); + + foundationApi.subscribe('resize', function () { + // only run update on current element + ico.update(element[0]); + }); + + // handle dynamic updating of src + if (scope.dynSrc) { + scope.$watch('dynSrc', function (newVal, oldVal) { + if (newVal && newVal !== oldVal) { + reinjectSvg(scope.dynSrc); + } + }); + } + // handle dynamic updating of icon + if (scope.dynIcon) { + scope.$watch('dynIcon', function (newVal, oldVal) { + if (newVal && newVal !== oldVal) { + reinjectSvg(assetPath + scope.dynIcon + '.svg'); + } + }); + } + + function reinjectSvg(newSrc) { + if (svgElement) { + // set html + svgElement.empty(); + svgElement.append(angular.element(contents)); + + // set new source + svgElement.attr('data-src', newSrc); + + // reinject + injectSvg(svgElement[0]); + } + } + + function injectSvg(element) { + ico.inject(element, { + each: function (injectedElem) { + // compile injected svg + var angElem = angular.element(injectedElem); + svgElement = $compile(angElem)(angElem.scope()); + } + }); + } + } + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.interchange', ['foundation.core', 'foundation.mediaquery']) + .directive('zfInterchange', zfInterchange) + ; + + zfInterchange.$inject = [ '$compile', '$http', '$templateCache', 'FoundationApi', 'FoundationMQ']; + + function zfInterchange($compile, $http, $templateCache, foundationApi, foundationMQ) { + + var directive = { + restrict: 'EA', + transclude: 'element', + scope: { + position: '@' + }, + replace: true, + template: '
', + link: link + }; + + return directive; + + function link(scope, element, attrs, ctrl, transclude) { + var childScope, current, scenarios, innerTemplates; + + var globalQueries = foundationMQ.getMediaQueries(); + + //setup + foundationApi.subscribe('resize', function(msg) { + transclude(function(clone, newScope) { + if(!scenarios || !innerTemplates) { + collectInformation(clone); + } + + var ruleMatches = foundationMQ.match(scenarios); + var scenario = ruleMatches.length === 0 ? null : scenarios[ruleMatches[0].ind]; + + //this could use some love + if(scenario && checkScenario(scenario)) { + var compiled; + + if(childScope) { + childScope.$destroy(); + childScope = null; + } + + if(typeof scenario.templ !== 'undefined') { + childScope = newScope; + + //temp container + var tmp = document.createElement('div'); + tmp.appendChild(innerTemplates[scenario.templ][0]); + + element.html(tmp.innerHTML); + $compile(element.contents())(childScope); + current = scenario; + } else { + var loader = templateLoader(scenario.src); + loader.success(function(html) { + childScope = newScope; + element.html(html); + }).then(function(){ + $compile(element.contents())(childScope); + current = scenario; + }); + } + } + }); + + }); + + //init + foundationApi.publish('resize', 'initial resize'); + + function templateLoader(templateUrl) { + return $http.get(templateUrl, {cache: $templateCache}); + } + + function collectInformation(el) { + var data = foundationMQ.collectScenariosFromElement(el); + + scenarios = data.scenarios; + innerTemplates = data.templates; + } + + function checkScenario(scenario) { + return !current || current !== scenario; + } + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.modal', ['foundation.core']) + .directive('zfModal', modalDirective) + .factory('ModalFactory', ModalFactory) + ; + + FoundationModal.$inject = ['FoundationApi', 'ModalFactory']; + + function FoundationModal(foundationApi, ModalFactory) { + var service = {}; + + service.activate = activate; + service.deactivate = deactivate; + service.newModal = newModal; + + return service; + + //target should be element ID + function activate(target) { + foundationApi.publish(target, 'show'); + } + + //target should be element ID + function deactivate(target) { + foundationApi.publish(target, 'hide'); + } + + //new modal has to be controlled via the new instance + function newModal(config) { + return new ModalFactory(config); + } + } + + modalDirective.$inject = ['FoundationApi']; + + function modalDirective(foundationApi) { + + var directive = { + restrict: 'EA', + templateUrl: 'components/modal/modal.html', + transclude: true, + scope: true, + replace: true, + compile: compile + }; + + return directive; + + function compile(tElement, tAttrs, transclude) { + var type = 'modal'; + + return { + pre: preLink, + post: postLink + }; + + function preLink(scope, iElement, iAttrs, controller) { + iAttrs.$set('zf-closable', type); + } + + function postLink(scope, element, attrs) { + var dialog = angular.element(element.children()[0]); + + scope.active = scope.active || false; + scope.overlay = attrs.overlay === 'false' ? false : true; + scope.overlayClose = attrs.overlayClose === 'false' ? false : true; + + var animationIn = attrs.animationIn || 'fadeIn'; + var animationOut = attrs.animationOut || 'fadeOut'; + + var overlayIn = 'fadeIn'; + var overlayOut = 'fadeOut'; + + scope.hideOverlay = function() { + if(scope.overlayClose) { + scope.hide(); + } + }; + + scope.hide = function() { + scope.active = false; + animate(); + return; + }; + + scope.show = function() { + scope.active = true; + animate(); + dialog.tabIndex = -1; + dialog[0].focus(); + return; + }; + + scope.toggle = function() { + scope.active = !scope.active; + animate(); + return; + }; + + init(); + + //setup + foundationApi.subscribe(attrs.id, function(msg) { + if(msg === 'show' || msg === 'open') { + scope.show(); + } else if (msg === 'close' || msg === 'hide') { + scope.hide(); + } else if (msg === 'toggle') { + scope.toggle(); + } + + if (scope.$root && !scope.$root.$$phase) { + scope.$apply(); + } + + return; + }); + + function animate() { + //animate both overlay and dialog + if(!scope.overlay) { + element.css('background', 'transparent'); + } + + foundationApi.animate(element, scope.active, overlayIn, overlayOut); + foundationApi.animate(dialog, scope.active, animationIn, animationOut); + } + + function init() { + if(scope.active) { + scope.show(); + } + } + } + } + } + + ModalFactory.$inject = ['$http', '$templateCache', '$rootScope', '$compile', '$timeout', '$q', 'FoundationApi']; + + function ModalFactory($http, $templateCache, $rootScope, $compile, $timeout, $q, foundationApi) { + return modalFactory; + + function modalFactory(config) { + var self = this, //for prototype functions + container = angular.element(config.container || document.body), + id = config.id || foundationApi.generateUuid(), + attached = false, + destroyed = false, + html, + element, + fetched, + scope, + contentScope + ; + + var props = [ + 'animationIn', + 'animationOut', + 'overlay', + 'overlayClose' + ]; + + if(config.templateUrl) { + //get template + fetched = $http.get(config.templateUrl, { + cache: $templateCache + }).then(function (response) { + html = response.data; + assembleDirective(); + }); + + } else if(config.template) { + //use provided template + fetched = true; + html = config.template; + assembleDirective(); + } + + self.activate = activate; + self.deactivate = deactivate; + self.toggle = toggle; + self.destroy = destroy; + + + return { + activate: activate, + deactivate: deactivate, + toggle: toggle, + destroy: destroy + }; + + function checkStatus() { + if(destroyed) { + throw "Error: Modal was destroyed. Delete the object and create a new ModalFactory instance." + } + } + + function activate() { + checkStatus(); + $timeout(function() { + init(true); + foundationApi.publish(id, 'show'); + }, 0, false); + } + + function deactivate() { + checkStatus(); + $timeout(function() { + init(false); + foundationApi.publish(id, 'hide'); + }, 0, false); + } + + function toggle() { + checkStatus(); + $timeout(function() { + init(true); + foundationApi.publish(id, 'toggle'); + }, 0, false); + } + + function init(state) { + $q.when(fetched).then(function() { + if(!attached && html.length > 0) { + var modalEl = container.append(element); + + scope.active = state; + $compile(element)(scope); + + attached = true; + } + }); + } + + function assembleDirective() { + // check for duplicate elements to prevent factory from cloning modals + if (document.getElementById(id)) { + return; + } + + html = '' + html + ''; + + element = angular.element(html); + + scope = $rootScope.$new(); + + // account for directive attributes + for(var i = 0; i < props.length; i++) { + var prop = props[i]; + + if(config[prop]) { + switch (prop) { + case 'animationIn': + element.attr('animation-in', config[prop]); + break; + case 'animationOut': + element.attr('animation-out', config[prop]); + break; + default: + element.attr(prop, config[prop]); + } + } + } + // access view scope variables + if (config.contentScope) { + contentScope = config.contentScope; + for (var prop in config.contentScope) { + if (config.contentScope.hasOwnProperty(prop)) { + scope[prop] = config.contentScope[prop]; + } + } + } + } + + function destroy() { + self.deactivate(); + setTimeout(function() { + scope.$destroy(); + element.remove(); + destroyed = true; + }, 3000); + foundationApi.unsubscribe(id); + } + + } + + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.notification', ['foundation.core']) + .controller('ZfNotificationController', ZfNotificationController) + .directive('zfNotificationSet', zfNotificationSet) + .directive('zfNotification', zfNotification) + .directive('zfNotificationStatic', zfNotificationStatic) + .directive('zfNotify', zfNotify) + .factory('NotificationFactory', NotificationFactory) + .service('FoundationNotification', FoundationNotification) + ; + + FoundationNotification.$inject = ['FoundationApi', 'NotificationFactory']; + + function FoundationNotification(foundationApi, NotificationFactory) { + var service = {}; + + service.activate = activate; + service.deactivate = deactivate; + + return service; + + //target should be element ID + function activate(target) { + foundationApi.publish(target, 'show'); + } + + //target should be element ID + function deactivate(target) { + foundationApi.publish(target, 'hide'); + } + + function toggle(target) { + foundationApi.publish(target, 'toggle'); + } + + function createNotificationSet(config) { + return new NotificationFactory(config); + } + } + + + ZfNotificationController.$inject = ['$scope', 'FoundationApi']; + + function ZfNotificationController($scope, foundationApi) { + var controller = this; + controller.notifications = $scope.notifications = $scope.notifications || []; + + controller.addNotification = function(info) { + var id = foundationApi.generateUuid(); + info.id = id; + $scope.notifications.push(info); + }; + + controller.removeNotification = function(id) { + $scope.notifications.forEach(function(notification) { + if(notification.id === id) { + var ind = $scope.notifications.indexOf(notification); + $scope.notifications.splice(ind, 1); + } + }); + }; + + controller.clearAll = function() { + while($scope.notifications.length > 0) { + $scope.notifications.pop(); + } + }; + } + + zfNotificationSet.$inject = ['FoundationApi']; + + function zfNotificationSet(foundationApi) { + var directive = { + restrict: 'EA', + templateUrl: 'components/notification/notification-set.html', + controller: 'ZfNotificationController', + replace: true, + scope: { + position: '@' + }, + link: link + }; + + return directive; + + function link(scope, element, attrs, controller) { + scope.position = scope.position ? scope.position.split(' ').join('-') : 'top-right'; + + foundationApi.subscribe(attrs.id, function(msg) { + if(msg === 'clearall') { + controller.clearAll(); + } + else { + controller.addNotification(msg); + if (!scope.$root.$$phase) { + scope.$apply(); + } + } + }); + } + } + + zfNotification.$inject = ['FoundationApi']; + + function zfNotification(foundationApi) { + var directive = { + restrict: 'EA', + templateUrl: 'components/notification/notification.html', + replace: true, + transclude: true, + require: '^zfNotificationSet', + controller: function() { }, + scope: { + title: '=?', + content: '=?', + image: '=?', + notifId: '=', + color: '=?', + autoclose: '=?' + }, + compile: compile + }; + + return directive; + + function compile() { + + return { + pre: preLink, + post: postLink + }; + + function preLink(scope, iElement, iAttrs) { + iAttrs.$set('zf-closable', 'notification'); + } + + function postLink(scope, element, attrs, controller) { + scope.active = false; + var animationIn = attrs.animationIn || 'fadeIn'; + var animationOut = attrs.animationOut || 'fadeOut'; + var hammerElem; + + //due to dynamic insertion of DOM, we need to wait for it to show up and get working! + setTimeout(function() { + scope.active = true; + foundationApi.animate(element, scope.active, animationIn, animationOut); + }, 50); + + scope.hide = function() { + scope.active = false; + foundationApi.animate(element, scope.active, animationIn, animationOut); + setTimeout(function() { + controller.removeNotification(scope.notifId); + }, 50); + }; + + // close if autoclose + if (scope.autoclose) { + setTimeout(function() { + if (scope.active) { + scope.hide(); + } + }, parseInt(scope.autoclose)); + }; + + // close on swipe + if (Hammer) { + hammerElem = new Hammer(element[0]); + // set the options for swipe (to make them a bit more forgiving in detection) + hammerElem.get('swipe').set({ + direction: Hammer.DIRECTION_ALL, + threshold: 5, // this is how far the swipe has to travel + velocity: 0.5 // and this is how fast the swipe must travel + }); + } + + hammerElem.on('swipe', function() { + if (scope.active) { + scope.hide(); + } + }); + } + } + } + + zfNotificationStatic.$inject = ['FoundationApi']; + + function zfNotificationStatic(foundationApi) { + var directive = { + restrict: 'EA', + templateUrl: 'components/notification/notification-static.html', + replace: true, + transclude: true, + scope: { + title: '@?', + content: '@?', + image: '@?', + color: '@?', + autoclose: '@?' + }, + compile: compile + }; + + return directive; + + function compile() { + var type = 'notification'; + + return { + pre: preLink, + post: postLink + }; + + function preLink(scope, iElement, iAttrs, controller) { + iAttrs.$set('zf-closable', type); + } + + function postLink(scope, element, attrs, controller) { + scope.position = attrs.position ? attrs.position.split(' ').join('-') : 'top-right'; + + var animationIn = attrs.animationIn || 'fadeIn'; + var animationOut = attrs.animationOut || 'fadeOut'; + + //setup + foundationApi.subscribe(attrs.id, function(msg) { + if(msg == 'show' || msg == 'open') { + scope.show(); + // close if autoclose + if (scope.autoclose) { + setTimeout(function() { + if (scope.active) { + scope.hide(); + } + }, parseInt(scope.autoclose)); + }; + } else if (msg == 'close' || msg == 'hide') { + scope.hide(); + } else if (msg == 'toggle') { + scope.toggle(); + // close if autoclose + if (scope.autoclose) { + setTimeout(function() { + if (scope.active) { + scope.toggle(); + } + }, parseInt(scope.autoclose)); + }; + } + + foundationApi.animate(element, scope.active, animationIn, animationOut); + scope.$apply(); + + return; + }); + + scope.hide = function() { + scope.active = false; + foundationApi.animate(element, scope.active, animationIn, animationOut); + return; + }; + + scope.show = function() { + scope.active = true; + foundationApi.animate(element, scope.active, animationIn, animationOut); + return; + }; + + scope.toggle = function() { + scope.active = !scope.active; + foundationApi.animate(element, scope.active, animationIn, animationOut); + return; + }; + + } + } + } + + zfNotify.$inject = ['FoundationApi']; + + function zfNotify(foundationApi) { + var directive = { + restrict: 'A', + scope: { + title: '@?', + content: '@?', + color: '@?', + image: '@?', + autoclose: '@?' + }, + link: link + }; + + return directive; + + function link(scope, element, attrs, controller) { + element.on('click', function(e) { + foundationApi.publish(attrs.zfNotify, { + title: scope.title, + content: scope.content, + color: scope.color, + image: scope.image, + autoclose: scope.autoclose + }); + e.preventDefault(); + }); + } + } + + NotificationFactory.$inject = ['$http', '$templateCache', '$rootScope', '$compile', '$timeout', 'FoundationApi']; + + function NotificationFactory($http, $templateCache, $rootScope, $compile, $timeout, foundationApi) { + return notificationFactory; + + function notificationFactory(config) { + var self = this, //for prototype functions + container = angular.element(config.container || document.body), + id = config.id || foundationApi.generateUuid(), + attached = false, + destroyed = false, + html, + element, + scope, + contentScope + ; + + var props = [ + 'position' + ]; + + assembleDirective(); + + self.addNotification = addNotification; + self.clearAll = clearAll; + self.destroy = destroy; + + return { + addNotification: addNotification, + clearAll: clearAll, + destroy: destroy + }; + + function checkStatus() { + if(destroyed) { + throw "Error: Notification Set was destroyed. Delete the object and create a new NotificationFactory instance." + } + } + + function addNotification(notification) { + checkStatus(); + $timeout(function() { + foundationApi.publish(id, notification); + }, 0, false); + } + + function clearAll() { + checkStatus(); + $timeout(function() { + foundationApi.publish(id, 'clearall'); + }, 0, false); + } + + function init(state) { + if(!attached && html.length > 0) { + var modalEl = container.append(element); + + scope.active = state; + $compile(element)(scope); + + attached = true; + } + } + + function assembleDirective() { + // check for duplicate element to prevent factory from cloning notification sets + if (document.getElementById(id)) { + return; + } + html = ''; + + element = angular.element(html); + + scope = $rootScope.$new(); + + for(var i = 0; i < props.length; i++) { + if(config[props[i]]) { + element.attr(props[i], config[props[i]]); + } + } + + // access view scope variables + if (config.contentScope) { + contentScope = config.contentScope; + for (var prop in contentScope) { + if (contentScope.hasOwnProperty(prop)) { + scope[prop] = contentScope[prop]; + } + } + } + init(true); + } + + function destroy() { + self.clearAll(); + setTimeout(function() { + scope.$destroy(); + element.remove(); + destroyed = true; + }, 3000); + foundationApi.unsubscribe(id); + } + + } + + } +})(); + +(function() { + 'use strict'; + + angular.module('foundation.offcanvas', ['foundation.core']) + .directive('zfOffcanvas', zfOffcanvas) + .service('FoundationOffcanvas', FoundationOffcanvas) + ; + + FoundationOffcanvas.$inject = ['FoundationApi']; + + function FoundationOffcanvas(foundationApi) { + var service = {}; + + service.activate = activate; + service.deactivate = deactivate; + + return service; + + //target should be element ID + function activate(target) { + foundationApi.publish(target, 'show'); + } + + //target should be element ID + function deactivate(target) { + foundationApi.publish(target, 'hide'); + } + + function toggle(target) { + foundationApi.publish(target, 'toggle'); + } + } + + zfOffcanvas.$inject = ['FoundationApi']; + + function zfOffcanvas(foundationApi) { + var directive = { + restrict: 'EA', + templateUrl: 'components/offcanvas/offcanvas.html', + transclude: true, + scope: { + position: '@' + }, + replace: true, + compile: compile + }; + + return directive; + + function compile(tElement, tAttrs, transclude) { + var type = 'offcanvas'; + + return { + pre: preLink, + post: postLink + } + + function preLink(scope, iElement, iAttrs, controller) { + iAttrs.$set('zf-closable', type); + document.body.classList.add('has-off-canvas'); + } + + function postLink(scope, element, attrs) { + scope.position = scope.position || 'left'; + + scope.active = false; + //setup + foundationApi.subscribe(attrs.id, function(msg) { + if(msg === 'show' || msg === 'open') { + scope.show(); + } else if (msg === 'close' || msg === 'hide') { + scope.hide(); + } else if (msg === 'toggle') { + scope.toggle(); + } + + if (!scope.$root.$$phase) { + scope.$apply(); + } + + return; + }); + + scope.hide = function() { + scope.active = false; + return; + }; + + scope.show = function() { + scope.active = true; + return; + }; + + scope.toggle = function() { + scope.active = !scope.active; + return; + }; + } + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.panel', ['foundation.core']) + .directive('zfPanel', zfPanel) + .service('FoundationPanel', FoundationPanel) + ; + + FoundationPanel.$inject = ['FoundationApi']; + + function FoundationPanel(foundationApi) { + var service = {}; + + service.activate = activate; + service.deactivate = deactivate; + + return service; + + //target should be element ID + function activate(target) { + foundationApi.publish(target, 'show'); + } + + //target should be element ID + function deactivate(target) { + foundationApi.publish(target, 'hide'); + } + } + + zfPanel.$inject = ['FoundationApi', '$window']; + + function zfPanel(foundationApi, $window) { + var directive = { + restrict: 'EA', + templateUrl: 'components/panel/panel.html', + transclude: true, + scope: { + position: '@?' + }, + replace: true, + compile: compile + }; + + return directive; + + function compile(tElement, tAttrs, transclude) { + var type = 'panel'; + + return { + pre: preLink, + post: postLink + }; + + function preLink(scope, iElement, iAttrs, controller) { + iAttrs.$set('zf-closable', type); + scope.position = scope.position || 'left'; + scope.positionClass = 'panel-' + scope.position; + } + + function postLink(scope, element, attrs) { + scope.active = false; + var animationIn, animationOut; + var globalQueries = foundationApi.getSettings().mediaQueries; + + //urgh, there must be a better way + if(scope.position === 'left') { + animationIn = attrs.animationIn || 'slideInRight'; + animationOut = attrs.animationOut || 'slideOutLeft'; + } else if (scope.position === 'right') { + animationIn = attrs.animationIn || 'slideInLeft'; + animationOut = attrs.animationOut || 'slideOutRight'; + } else if (scope.position === 'top') { + animationIn = attrs.animationIn || 'slideInDown'; + animationOut = attrs.animationOut || 'slideOutUp'; + } else if (scope.position === 'bottom') { + animationIn = attrs.animationIn || 'slideInUp'; + animationOut = attrs.animationOut || 'slideOutBottom'; + } + + + //setup + foundationApi.subscribe(attrs.id, function(msg) { + var panelPosition = $window.getComputedStyle(element[0]).getPropertyValue("position"); + + // patch to prevent panel animation on larger screen devices + if (panelPosition !== 'absolute') { + return; + } + + if(msg == 'show' || msg == 'open') { + scope.show(); + } else if (msg == 'close' || msg == 'hide') { + scope.hide(); + } else if (msg == 'toggle') { + scope.toggle(); + } + + if (!scope.$root.$$phase) { + scope.$apply(); + } + + return; + }); + + scope.hide = function() { + if(scope.active){ + scope.active = false; + foundationApi.animate(element, scope.active, animationIn, animationOut); + } + + return; + }; + + scope.show = function() { + if(!scope.active){ + scope.active = true; + foundationApi.animate(element, scope.active, animationIn, animationOut); + } + + return; + }; + + scope.toggle = function() { + scope.active = !scope.active; + foundationApi.animate(element, scope.active, animationIn, animationOut); + + return; + }; + + element.on('click', function(e) { + //check sizing + var srcEl = e.srcElement; + + if(!matchMedia(globalQueries.medium).matches && srcEl.href && srcEl.href.length > 0) { + //hide element if it can't match at least medium + scope.hide(); + foundationApi.animate(element, scope.active, animationIn, animationOut); + } + }); + } + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.popup', ['foundation.core']) + .directive('zfPopup', zfPopup) + .directive('zfPopupToggle', zfPopupToggle) + .service('FoundationPopup', FoundationPopup) + ; + + FoundationPopup.$inject = ['FoundationApi']; + + function FoundationPopup(foundationApi) { + var service = {}; + + service.activate = activate; + service.deactivate = deactivate; + + return service; + + //target should be element ID + function activate(target) { + foundationApi.publish(target, 'show'); + } + + //target should be element ID + function deactivate(target) { + foundationApi.publish(target, 'hide'); + } + + function toggle(target, popupTarget) { + foundationApi.publish(target, ['toggle', popupTarget]); + } + } + + zfPopup.$inject = ['FoundationApi']; + + function zfPopup(foundationApi) { + var directive = { + restrict: 'EA', + transclude: true, + replace: true, + templateUrl: 'components/popup/popup.html', + scope: { + pinTo: '@?', + pinAt: '@?', + target: '@?' + }, + compile: compile + }; + + return directive; + + function compile() { + return { + pre: preLink, + post: postLink + }; + + function preLink(scope, iElement, iAttrs) { + iAttrs.$set('zf-closable', 'popup'); + } + + function postLink(scope, element, attrs) { + scope.active = false; + scope.target = scope.target || false; + + var attachment = scope.pinTo || 'top center'; + var targetAttachment = scope.pinAt || 'bottom center'; + var tetherInit = false; + var tether = {}; + + //setup + foundationApi.subscribe(attrs.id, function(msg) { + if(msg[0] === 'show' || msg[0] === 'open') { + scope.show(msg[1]); + } else if (msg[0] === 'close' || msg[0] === 'hide') { + scope.hide(); + } else if (msg[0] === 'toggle') { + scope.toggle(msg[1]); + } + + scope.$apply(); + + return; + }); + + + scope.hide = function() { + scope.active = false; + tetherElement(); + tether.disable(); + return; + }; + + scope.show = function(newTarget) { + scope.active = true; + tetherElement(newTarget); + tether.enable(); + + return; + }; + + scope.toggle = function(newTarget) { + scope.active = !scope.active; + tetherElement(newTarget); + + if(scope.active) { + tether.enable(); + } else { + tether.disable(); + } + + return; + }; + + function tetherElement(target) { + if(tetherInit) { + return; + } + + scope.target = scope.target ? document.getElementById(scope.target) : document.getElementById(target); + + tether = new Tether({ + element: element[0], + target: scope.target, + attachment: attachment, + targetAttachment: targetAttachment, + enable: false + }); + + tetherInit = true; + } + + } + } + } + + zfPopupToggle.$inject = ['FoundationApi']; + + function zfPopupToggle(foundationApi) { + var directive = { + restrict: 'A', + link: link + }; + + return directive; + + function link(scope, element, attrs) { + var target = attrs.zfPopupToggle; + var id = attrs.id || foundationApi.generateUuid(); + attrs.$set('id', id); + + element.on('click', function(e) { + foundationApi.publish(target, ['toggle', id]); + e.preventDefault(); + }); + } + } + +})(); + +(function() { + 'use strict'; + + angular.module('foundation.tabs', ['foundation.core']) + .controller('ZfTabsController', ZfTabsController) + .directive('zfTabs', zfTabs) + .directive('zfTabContent', zfTabContent) + .directive('zfTab', zfTab) + .directive('zfTabIndividual', zfTabIndividual) + .directive('zfTabHref', zfTabHref) + .directive('zfTabCustom', zfTabCustom) + .directive('zfTabContentCustom', zfTabContentCustom) + .service('FoundationTabs', FoundationTabs) + ; + + FoundationTabs.$inject = ['FoundationApi']; + + function FoundationTabs(foundationApi) { + var service = {}; + + service.activate = activate; + + return service; + + //target should be element ID + function activate(target) { + foundationApi.publish(target, 'show'); + } + + } + + ZfTabsController.$inject = ['$scope', 'FoundationApi']; + + function ZfTabsController($scope, foundationApi) { + var controller = this; + var tabs = controller.tabs = $scope.tabs = []; + var id = ''; + + controller.select = function(selectTab) { + tabs.forEach(function(tab) { + tab.active = false; + tab.scope.active = false; + + if(tab.scope === selectTab) { + foundationApi.publish(id, ['activate', tab]); + + tab.active = true; + tab.scope.active = true; + } + }); + + }; + + controller.addTab = function addTab(tabScope) { + tabs.push({ scope: tabScope, active: false, parentContent: controller.id }); + + if(tabs.length === 1) { + tabs[0].active = true; + tabScope.active = true; + } + }; + + controller.getId = function() { + return id; + }; + + controller.setId = function(newId) { + id = newId; + }; + } + + zfTabs.$inject = ['FoundationApi']; + + function zfTabs(foundationApi) { + var directive = { + restrict: 'EA', + transclude: 'true', + replace: true, + templateUrl: 'components/tabs/tabs.html', + controller: 'ZfTabsController', + scope: { + displaced: '@?' + }, + link: link + }; + + return directive; + + function link(scope, element, attrs, controller) { + scope.id = attrs.id || foundationApi.generateUuid(); + scope.showTabContent = scope.displaced !== 'true'; + attrs.$set('id', scope.id); + controller.setId(scope.id); + + //update tabs in case tab-content doesn't have them + var updateTabs = function() { + foundationApi.publish(scope.id + '-tabs', scope.tabs); + }; + + foundationApi.subscribe(scope.id + '-get-tabs', function() { + updateTabs(); + }); + } + } + + zfTabContent.$inject = ['FoundationApi']; + + function zfTabContent(foundationApi) { + var directive = { + restrict: 'A', + transclude: 'true', + replace: true, + scope: { + tabs: '=?', + target: '@' + }, + templateUrl: 'components/tabs/tab-content.html', + link: link + }; + + return directive; + + function link(scope, element, attrs, ctrl) { + scope.tabs = scope.tabs || []; + var id = scope.target; + + foundationApi.subscribe(id, function(msg) { + if(msg[0] === 'activate') { + var tabId = msg[1]; + scope.tabs.forEach(function (tab) { + tab.scope.active = false; + tab.active = false; + + if(tab.scope.id === id) { + tab.scope.active = true; + tab.active = true; + } + }); + } + }); + + //if tabs empty, request tabs + if(scope.tabs.length === 0) { + foundationApi.subscribe(id + '-tabs', function(tabs) { + scope.tabs = tabs; + }); + + foundationApi.publish(id + '-get-tabs', ''); + } + } + } + + zfTab.$inject = ['FoundationApi']; + + function zfTab(foundationApi) { + var directive = { + restrict: 'EA', + templateUrl: 'components/tabs/tab.html', + transclude: true, + scope: { + title: '@' + }, + require: '^zfTabs', + replace: true, + link: link + }; + + return directive; + + function link(scope, element, attrs, controller, transclude) { + scope.id = attrs.id || foundationApi.generateUuid(); + scope.active = false; + scope.transcludeFn = transclude; + controller.addTab(scope); + + foundationApi.subscribe(scope.id, function(msg) { + if(msg === 'show' || msg === 'open' || msg === 'activate') { + scope.makeActive(); + } + }); + + scope.makeActive = function() { + controller.select(scope); + }; + } + } + + zfTabIndividual.$inject = ['FoundationApi']; + + function zfTabIndividual(foundationApi) { + var directive = { + restrict: 'EA', + transclude: 'true', + link: link + }; + + return directive; + + function link(scope, element, attrs, ctrl, transclude) { + var tab = scope.$eval(attrs.tab); + var id = tab.scope.id; + + tab.scope.transcludeFn(tab.scope, function(tabContent) { + element.append(tabContent); + }); + + foundationApi.subscribe(tab.scope.id, function(msg) { + foundationApi.publish(tab.parentContent, ['activate', tab.scope.id]); + scope.$apply(); + }); + + } + } + + //custom tabs + + zfTabHref.$inject = ['FoundationApi']; + + function zfTabHref(foundationApi) { + var directive = { + restrict: 'A', + replace: false, + link: link + } + + return directive; + + function link(scope, element, attrs, ctrl) { + var target = attrs.zfTabHref; + + foundationApi.subscribe(target, function(msg) { + if(msg === 'activate' || msg === 'show' || msg === 'open') { + makeActive(); + } + }); + + + element.on('click', function(e) { + foundationApi.publish(target, 'activate'); + makeActive(); + e.preventDefault(); + }); + + function makeActive() { + element.parent().children().removeClass('is-active'); + element.addClass('is-active'); + } + } + } + + zfTabCustom.$inject = ['FoundationApi']; + + function zfTabCustom(foundationApi) { + var directive = { + restrict: 'A', + replace: false, + link: link + }; + + return directive; + + function link(scope, element, attrs, ctrl, transclude) { + var children = element.children(); + angular.element(children[0]).addClass('is-active'); + } + } + + zfTabContentCustom.$inject = ['FoundationApi']; + + function zfTabContentCustom(foundationApi) { + return { + restrict: 'A', + link: link + }; + + function link(scope, element, attrs) { + var tabs = []; + var children = element.children(); + + angular.forEach(children, function(node) { + if(node.id) { + var tabId = node.id; + tabs.push(tabId); + foundationApi.subscribe(tabId, function(msg) { + if(msg === 'activate' || msg === 'show' || msg === 'open') { + activateTabs(tabId); + } + }); + + if(tabs.length === 1) { + var el = angular.element(node); + el.addClass('is-active'); + } + } + }); + + function activateTabs(tabId) { + var tabNodes = element.children(); + angular.forEach(tabNodes, function(node) { + var el = angular.element(node); + el.removeClass('is-active'); + if(el.attr('id') === tabId) { + el.addClass('is-active'); + } + + }); + } + } + } + +})(); + +(function() { + 'use strict'; + + // imports all components and dependencies under a single namespace + + angular.module('foundation', [ + 'foundation.core', + 'foundation.mediaquery', + 'foundation.accordion', + 'foundation.actionsheet', + 'foundation.common', + 'foundation.iconic', + 'foundation.interchange', + 'foundation.modal', + 'foundation.notification', + 'foundation.offcanvas', + 'foundation.panel', + 'foundation.popup', + 'foundation.tabs' + ]); + +})();