const ERROR = "error"; const OK = "ok"; const INFO = "info"; window.access_token = ""; window.stewart_access_token = ""; window.admin_access_token = ""; window.gala_currency = ""; window.gala_raffle_ticket_amount = 0; window.activity_ticket_cost = 20; window.gala_id = ""; window.gala_guest_id = ""; window.gala_guest_first_name = ""; window.gala_guest_last_name = ""; window.gala_stewart_id = ""; window.gala_stewart_first_name = ""; window.gala_admin_id = ""; window.gala_admin_first_name = ""; window.gala_rsvp_total = 0; window.facts = new Array(); window.facts['en'] = new Array ( "53.3% of the female population in India have no more than 8 years of education - Apnalaya's work helps address this challenge.", "Over 50% of LGBTQ youth are subject to sex trafficking after 72hrs of homelessness - the Ali Forney Center’s work helps address this challenge.", "64% of privately educated A level students gain a place at a highly-selective university in the UK, while 19% of A level students in non-selective state school pupils go on to study at a highly-selective university - The Brilliant Club’s work helps address this challenge.", "42% of street children in Thailand are working children, and 23% of these which are aged 0-5 (43% aged 6-14, 34% aged 15-18) - Friend’s International’s work helps address this challenge.", "There are no adequate public care services available for the 49,000 children under 18 in the UK who live with a life-threatening condition - Haven House’s work helps address this challenge.", "Among the under-18 inhabitants of Sihanoukville, Cambodia, 21.4% are vulnerable to poverty, leading to a high number of street working and street living children - M’Lop Tapang works to protect vulnerable children and youth.", "There are 1.1 million HIV/AIDS orphans in Uganda - Nyaka’s work helps address their needs.", "Nearly 2 in 3 of all unemployed in Vietnam are young people aged 15-24 - Reach’s work helps address their needs.", "23% of youth aged 15 to 24 years old are unemployed in France - Simplon.co’s work helps address this challenge.", "212,000 jobs will be created in the digital sector by 2022 - Simplon.co’s work helps address this challenge.", "In 2015, there were 45,000 maternal deaths in India, accounting for 15% of the global figure - Sneha’s work helps address this challenge.", "45.5% of children in Mumbai slums suffer from malnutrition - Sneha’s work helps address this challenge.", "In Belgium the unemployment rate is close to 7% - the rate is more than 2x as high for non-European youth from immigrant backgrounds - Duo for a Job’s work helps address this challenge.", "About 11,100 children are in the foster care system in New York City, and 1 in 5 will become homeless after age 18, with less than 3% earning a college degree - Lawyers for Children’s work helps support these youth.", "In Africa, there are only 2.3 healthcare workers per a population of 1,000, compared to 24 per 1,000 in the Americas - Living Goods’ work helps address this challenge.", "Most of the population of Kibera, which is one of the largest slums in the world, live under $1 per day - Carolina for Libera’s work helps address this challenge.", "In the U.S., only 38% of students graduating high school are prepared for the literacy demands of college - CommonLit’s work helps address this challenge.", "1 in 4 college freshmen had to enroll in remedial coursework - ComonLit’s work helps address this challenge.", "870 million children are in need of STH treatment — worm infections disproportionately affect the poor - Deworm the World’s work helps address this.", "STH (worm infection) causes severe malnutrition among many Kenyan children below 5 years old. This can lead to negative impacts on school attendance, test scores and future earnings as adults. Deworm the World’s work helps address this.", "India has over 3 million sex workers, and an estimated 1.2 million are involved in prostitution - Prerana’s work helps address this challenge.", "The UK youth unemployment rate has been 3 times higher than the rate of unemployed adults for over a decade - Street League’s work helps address this challenge.", "843,000 youth are NEET in the UK (Not in Education, Employment, or Training) - Thinkforward’s work helps support these youth.", "Youth who are NEET for more than 6 months are more likely to be out of work again in the future and to have a criminal record - Thinkforward’s work helps support these youth.", "NEET youth cost an estimate £34 billion to the economy and society - Thinkforward’s work helps support these youth.", "Less than 1% of refugees attend university (compared to 34% of youth globally) - Kiron’s work helps address this challenge.", "Refugees have 4 barriers preventing them from accessing higher education: cost of attendance, legal status, college’s capacity to accept them, and lack of knowledge of German - Kiron’s work helps address this challenge.", "1 in 4 of 16 million Thai students are underserved - Learn Education’s work helps support these youth.", "300,000 Students drop out of basic education every year - Learn Education’s work helps support these youth.", "2/3 of kids leave 8th grade with gaps in algebra - New Classrooms’ work helps address this challenge.", "Off-track students have only a 20% chance of catching up - New Classrooms’ work helps address this challenge.", "1/3 of students graduate high school ready for college - New Classrooms’ work helps address this challenge.", "54% of UK youth leave their home because either their parents or others are no longer willing to accommodate them - Depaul UK’s work supports this challenge.", "Less than 50% of U.S. foster youth will graduate from high school - Pivotal’s work supports these youth.", "176 million children in India are in urgent need of care and protection - Make a Difference’s work supports these youth.", "In 2016, among college youth 1 out of 3 felt too depressed to function - The Jed Foundation’s work helps support these youth.", "In Africa 1 in 4 women are affected by depression and 85% have no access to treatment - StrongMind’s work helps address this challenge." ); window.facts['fr'] = new Array( "En Inde, 53% des femmes passent moins de 8 ans dans le système éducatif. Apnalaya change la donne.", "Aux Etats-Unis, plus de 50% des LGBTQ sont victimes d’exploitation sexuelles dans leurs premières 72 heures à la rue. Ali Forney Center change la donne.", "Au Royaume-Uni, seulement 19% des lycéens de dernière année inscrits à l’école publique intègrent une université très sélective. The Brilliant Club change la donne.", "42% des enfants à la rue en Thaïlande exercent un travail. Friends International change la donne.", "Au Royaume-Uni, il n’existe aucun service public de soins adéquat pour les 49 000 mineurs qui souffrent d’une maladie grave. Haven House change la donne.", "A Sihanoukville (Cambodge), 21% des mineurs sont vulnérables à la pauvreté et un grand nombre d’enfants vivent dans la rue. M’lop Tapang change la donne.", "En Ouganda, il y a 1,1 millions d’orphelins liés au VIH/SIDA. Nyaka change la donne.", "Au Vietnam, près de 2 chômeurs sur 3 ont entre 15 et 24 ans. Reach change la donne.", "En France, 23% des jeunes de 15 à 24 ans sont au chômage. Simplon.co change la donne.", "En 2015, 45 000 Indiennes sont mortes en couche, soit 15% du niveau mondial. Sneha change la donne.", "En France, 44% des jeunes hommes de 15 à 24 ans issus de l’immigration extra-européenne sont au chômage, contre 19% pour les autres. Sport dans la Ville change la donne.", "En Belgique, le taux de chômage est deux fois plus élevé pour les jeunes issus de l’immigration extra-européenne que pour les autres. Duo for a Job change la donne.", "A New-York, 1 enfant étant passé par un centre d’accueil sur 5 se retrouve à la rue après ses 18 ans. Lawyers for Children change la donne.", "En Afrique, il y a seulement 2 professionnels de santé pour 1 000 habitants, contre 24 pour 1 000 sur le continent américain. Living Goods change la donne.", "La majeure partie de la population de Kibera (Kenya), l'un des plus grands bidonvilles du monde, vit avec moins de $1 par jour. Carolina for Kibera change la donne.", "Aux États-Unis, seulement 38% des étudiants quittent le lycée avec les connaissances requises pour l'enseignement supérieur. CommonLit change la donne.", "870 millions d’enfants dans le monde ont besoin de traitement contre les helminthiases, infections parasitaires qui touchent particulièrement les jeunes kényans. Deworm the World change la donne.", "En Inde, on estime qu’1,2 millions d’enfants sont impliqués dans la prostitution. Prerana change la donne.", "Au Royaume-Uni, depuis plus de dix ans, le chômage des jeunes est 3 fois supérieur à celui des adultes. Street League change la donne.", "Au Royaume-Uni, 643 000 jeunes ne sont ni étudiant, ni employé, ni stagiaire. Ces jeunes sont davantage susceptibles d’être au chômage et d’avoir un casier judiciaire par la suite. ThinkForward change la donne.", "En Allemagne, moins d’1% des réfugiés accèdent à l’université, contre 34 % des jeunes globalement. Kiron change la donne.", "En Thaïlande, 300.000 élèves décrochent dès l’école primaire chaque année. Learn Education change la donne.", "Aux Etats-Unis, 2/3 des enfants entrent en troisième avec des lacunes en algèbre. New Classrooms change la donne." ); // md5 !function(n){"use strict";function t(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function r(n,t){return n<>>32-t}function e(n,e,o,u,c,f){return t(r(t(t(e,n),t(u,f)),c),o)}function o(n,t,r,o,u,c,f){return e(t&r|~t&o,n,t,u,c,f)}function u(n,t,r,o,u,c,f){return e(t&o|r&~o,n,t,u,c,f)}function c(n,t,r,o,u,c,f){return e(t^r^o,n,t,u,c,f)}function f(n,t,r,o,u,c,f){return e(r^(t|~o),n,t,u,c,f)}function i(n,r){n[r>>5]|=128<>>9<<4)]=r;var e,i,a,d,h,l=1732584193,g=-271733879,v=-1732584194,m=271733878;for(e=0;e>5]>>>t%32&255);return r}function d(n){var t,r=[];for(r[(n.length>>2)-1]=void 0,t=0;t>5]|=(255&n.charCodeAt(t/8))<16&&(o=i(o,8*n.length)),r=0;r<16;r+=1)u[r]=909522486^o[r],c[r]=1549556828^o[r];return e=i(u.concat(d(t)),512+8*t.length),a(i(c.concat(e),640))}function g(n){var t,r,e="";for(r=0;r>>4&15)+"0123456789abcdef".charAt(15&t);return e}function v(n){return unescape(encodeURIComponent(n))}function m(n){return h(v(n))}function p(n){return g(m(n))}function s(n,t){return l(v(n),v(t))}function C(n,t){return g(s(n,t))}function A(n,t,r){return t?r?s(t,n):C(t,n):r?m(n):p(n)}"function"==typeof define&&define.amd?define(function(){return A}):"object"==typeof module&&module.exports?module.exports=A:n.md5=A}(this); // BEGIN MDL ;(function() { "use strict"; /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A component handler interface using the revealing module design pattern. * More details on this design pattern here: * https://github.com/jasonmayes/mdl-component-design-pattern * * @author Jason Mayes. */ /* exported componentHandler */ // Pre-defining the componentHandler interface, for closure documentation and // static verification. var componentHandler = { /** * Searches existing DOM for elements of our component type and upgrades them * if they have not already been upgraded. * * @param {string=} optJsClass the programatic name of the element class we * need to create a new instance of. * @param {string=} optCssClass the name of the CSS class elements of this * type will have. */ upgradeDom: function(optJsClass, optCssClass) {}, /** * Upgrades a specific element rather than all in the DOM. * * @param {!Element} element The element we wish to upgrade. * @param {string=} optJsClass Optional name of the class we want to upgrade * the element to. */ upgradeElement: function(element, optJsClass) {}, /** * Upgrades a specific list of elements rather than all in the DOM. * * @param {!Element|!Array|!NodeList|!HTMLCollection} elements * The elements we wish to upgrade. */ upgradeElements: function(elements) {}, /** * Upgrades all registered components found in the current DOM. This is * automatically called on window load. */ upgradeAllRegistered: function() {}, /** * Allows user to be alerted to any upgrades that are performed for a given * component type * * @param {string} jsClass The class name of the MDL component we wish * to hook into for any upgrades performed. * @param {function(!HTMLElement)} callback The function to call upon an * upgrade. This function should expect 1 parameter - the HTMLElement which * got upgraded. */ registerUpgradedCallback: function(jsClass, callback) {}, /** * Registers a class for future use and attempts to upgrade existing DOM. * * @param {componentHandler.ComponentConfigPublic} config the registration configuration */ register: function(config) {}, /** * Downgrade either a given node, an array of nodes, or a NodeList. * * @param {!Node|!Array|!NodeList} nodes */ downgradeElements: function(nodes) {} }; componentHandler = (function() { 'use strict'; /** @type {!Array} */ var registeredComponents_ = []; /** @type {!Array} */ var createdComponents_ = []; var componentConfigProperty_ = 'mdlComponentConfigInternal_'; /** * Searches registered components for a class we are interested in using. * Optionally replaces a match with passed object if specified. * * @param {string} name The name of a class we want to use. * @param {componentHandler.ComponentConfig=} optReplace Optional object to replace match with. * @return {!Object|boolean} * @private */ function findRegisteredClass_(name, optReplace) { for (var i = 0; i < registeredComponents_.length; i++) { if (registeredComponents_[i].className === name) { if (typeof optReplace !== 'undefined') { registeredComponents_[i] = optReplace; } return registeredComponents_[i]; } } return false; } /** * Returns an array of the classNames of the upgraded classes on the element. * * @param {!Element} element The element to fetch data from. * @return {!Array} * @private */ function getUpgradedListOfElement_(element) { var dataUpgraded = element.getAttribute('data-upgraded'); // Use `['']` as default value to conform the `,name,name...` style. return dataUpgraded === null ? [''] : dataUpgraded.split(','); } /** * Returns true if the given element has already been upgraded for the given * class. * * @param {!Element} element The element we want to check. * @param {string} jsClass The class to check for. * @returns {boolean} * @private */ function isElementUpgraded_(element, jsClass) { var upgradedList = getUpgradedListOfElement_(element); return upgradedList.indexOf(jsClass) !== -1; } /** * Create an event object. * * @param {string} eventType The type name of the event. * @param {boolean} bubbles Whether the event should bubble up the DOM. * @param {boolean} cancelable Whether the event can be canceled. * @returns {!Event} */ function createEvent_(eventType, bubbles, cancelable) { if ('CustomEvent' in window && typeof window.CustomEvent === 'function') { return new CustomEvent(eventType, { bubbles: bubbles, cancelable: cancelable }); } else { var ev = document.createEvent('Events'); ev.initEvent(eventType, bubbles, cancelable); return ev; } } /** * Searches existing DOM for elements of our component type and upgrades them * if they have not already been upgraded. * * @param {string=} optJsClass the programatic name of the element class we * need to create a new instance of. * @param {string=} optCssClass the name of the CSS class elements of this * type will have. */ function upgradeDomInternal(optJsClass, optCssClass) { if (typeof optJsClass === 'undefined' && typeof optCssClass === 'undefined') { for (var i = 0; i < registeredComponents_.length; i++) { upgradeDomInternal(registeredComponents_[i].className, registeredComponents_[i].cssClass); } } else { var jsClass = /** @type {string} */ (optJsClass); if (typeof optCssClass === 'undefined') { var registeredClass = findRegisteredClass_(jsClass); if (registeredClass) { optCssClass = registeredClass.cssClass; } } var elements = document.querySelectorAll('.' + optCssClass); for (var n = 0; n < elements.length; n++) { upgradeElementInternal(elements[n], jsClass); } } } /** * Upgrades a specific element rather than all in the DOM. * * @param {!Element} element The element we wish to upgrade. * @param {string=} optJsClass Optional name of the class we want to upgrade * the element to. */ function upgradeElementInternal(element, optJsClass) { // Verify argument type. if (!(typeof element === 'object' && element instanceof Element)) { throw new Error('Invalid argument provided to upgrade MDL element.'); } // Allow upgrade to be canceled by canceling emitted event. var upgradingEv = createEvent_('mdl-componentupgrading', true, true); element.dispatchEvent(upgradingEv); if (upgradingEv.defaultPrevented) { return; } var upgradedList = getUpgradedListOfElement_(element); var classesToUpgrade = []; // If jsClass is not provided scan the registered components to find the // ones matching the element's CSS classList. if (!optJsClass) { var classList = element.classList; registeredComponents_.forEach(function(component) { // Match CSS & Not to be upgraded & Not upgraded. if (classList.contains(component.cssClass) && classesToUpgrade.indexOf(component) === -1 && !isElementUpgraded_(element, component.className)) { classesToUpgrade.push(component); } }); } else if (!isElementUpgraded_(element, optJsClass)) { classesToUpgrade.push(findRegisteredClass_(optJsClass)); } // Upgrade the element for each classes. for (var i = 0, n = classesToUpgrade.length, registeredClass; i < n; i++) { registeredClass = classesToUpgrade[i]; if (registeredClass) { // Mark element as upgraded. upgradedList.push(registeredClass.className); element.setAttribute('data-upgraded', upgradedList.join(',')); var instance = new registeredClass.classConstructor(element); instance[componentConfigProperty_] = registeredClass; createdComponents_.push(instance); // Call any callbacks the user has registered with this component type. for (var j = 0, m = registeredClass.callbacks.length; j < m; j++) { registeredClass.callbacks[j](element); } if (registeredClass.widget) { // Assign per element instance for control over API element[registeredClass.className] = instance; } } else { throw new Error( 'Unable to find a registered component for the given class.'); } var upgradedEv = createEvent_('mdl-componentupgraded', true, false); element.dispatchEvent(upgradedEv); } } /** * Upgrades a specific list of elements rather than all in the DOM. * * @param {!Element|!Array|!NodeList|!HTMLCollection} elements * The elements we wish to upgrade. */ function upgradeElementsInternal(elements) { if (!Array.isArray(elements)) { if (elements instanceof Element) { elements = [elements]; } else { elements = Array.prototype.slice.call(elements); } } for (var i = 0, n = elements.length, element; i < n; i++) { element = elements[i]; if (element instanceof HTMLElement) { upgradeElementInternal(element); if (element.children.length > 0) { upgradeElementsInternal(element.children); } } } } /** * Registers a class for future use and attempts to upgrade existing DOM. * * @param {componentHandler.ComponentConfigPublic} config */ function registerInternal(config) { // In order to support both Closure-compiled and uncompiled code accessing // this method, we need to allow for both the dot and array syntax for // property access. You'll therefore see the `foo.bar || foo['bar']` // pattern repeated across this method. var widgetMissing = (typeof config.widget === 'undefined' && typeof config['widget'] === 'undefined'); var widget = true; if (!widgetMissing) { widget = config.widget || config['widget']; } var newConfig = /** @type {componentHandler.ComponentConfig} */ ({ classConstructor: config.constructor || config['constructor'], className: config.classAsString || config['classAsString'], cssClass: config.cssClass || config['cssClass'], widget: widget, callbacks: [] }); registeredComponents_.forEach(function(item) { if (item.cssClass === newConfig.cssClass) { throw new Error('The provided cssClass has already been registered: ' + item.cssClass); } if (item.className === newConfig.className) { throw new Error('The provided className has already been registered'); } }); if (config.constructor.prototype .hasOwnProperty(componentConfigProperty_)) { throw new Error( 'MDL component classes must not have ' + componentConfigProperty_ + ' defined as a property.'); } var found = findRegisteredClass_(config.classAsString, newConfig); if (!found) { registeredComponents_.push(newConfig); } } /** * Allows user to be alerted to any upgrades that are performed for a given * component type * * @param {string} jsClass The class name of the MDL component we wish * to hook into for any upgrades performed. * @param {function(!HTMLElement)} callback The function to call upon an * upgrade. This function should expect 1 parameter - the HTMLElement which * got upgraded. */ function registerUpgradedCallbackInternal(jsClass, callback) { var regClass = findRegisteredClass_(jsClass); if (regClass) { regClass.callbacks.push(callback); } } /** * Upgrades all registered components found in the current DOM. This is * automatically called on window load. */ function upgradeAllRegisteredInternal() { for (var n = 0; n < registeredComponents_.length; n++) { upgradeDomInternal(registeredComponents_[n].className); } } /** * Check the component for the downgrade method. * Execute if found. * Remove component from createdComponents list. * * @param {?componentHandler.Component} component */ function deconstructComponentInternal(component) { if (component) { var componentIndex = createdComponents_.indexOf(component); createdComponents_.splice(componentIndex, 1); var upgrades = component.element_.getAttribute('data-upgraded').split(','); var componentPlace = upgrades.indexOf(component[componentConfigProperty_].classAsString); upgrades.splice(componentPlace, 1); component.element_.setAttribute('data-upgraded', upgrades.join(',')); var ev = createEvent_('mdl-componentdowngraded', true, false); component.element_.dispatchEvent(ev); } } /** * Downgrade either a given node, an array of nodes, or a NodeList. * * @param {!Node|!Array|!NodeList} nodes */ function downgradeNodesInternal(nodes) { /** * Auxiliary function to downgrade a single node. * @param {!Node} node the node to be downgraded */ var downgradeNode = function(node) { createdComponents_.filter(function(item) { return item.element_ === node; }).forEach(deconstructComponentInternal); }; if (nodes instanceof Array || nodes instanceof NodeList) { for (var n = 0; n < nodes.length; n++) { downgradeNode(nodes[n]); } } else if (nodes instanceof Node) { downgradeNode(nodes); } else { throw new Error('Invalid argument provided to downgrade MDL nodes.'); } } // Now return the functions that should be made public with their publicly // facing names... return { upgradeDom: upgradeDomInternal, upgradeElement: upgradeElementInternal, upgradeElements: upgradeElementsInternal, upgradeAllRegistered: upgradeAllRegisteredInternal, registerUpgradedCallback: registerUpgradedCallbackInternal, register: registerInternal, downgradeElements: downgradeNodesInternal }; })(); /** * Describes the type of a registered component type managed by * componentHandler. Provided for benefit of the Closure compiler. * * @typedef {{ * constructor: Function, * classAsString: string, * cssClass: string, * widget: (string|boolean|undefined) * }} */ componentHandler.ComponentConfigPublic; // jshint ignore:line /** * Describes the type of a registered component type managed by * componentHandler. Provided for benefit of the Closure compiler. * * @typedef {{ * constructor: !Function, * className: string, * cssClass: string, * widget: (string|boolean), * callbacks: !Array * }} */ componentHandler.ComponentConfig; // jshint ignore:line /** * Created component (i.e., upgraded element) type as managed by * componentHandler. Provided for benefit of the Closure compiler. * * @typedef {{ * element_: !HTMLElement, * className: string, * classAsString: string, * cssClass: string, * widget: string * }} */ componentHandler.Component; // jshint ignore:line // Export all symbols, for the benefit of Closure compiler. // No effect on uncompiled code. componentHandler['upgradeDom'] = componentHandler.upgradeDom; componentHandler['upgradeElement'] = componentHandler.upgradeElement; componentHandler['upgradeElements'] = componentHandler.upgradeElements; componentHandler['upgradeAllRegistered'] = componentHandler.upgradeAllRegistered; componentHandler['registerUpgradedCallback'] = componentHandler.registerUpgradedCallback; componentHandler['register'] = componentHandler.register; componentHandler['downgradeElements'] = componentHandler.downgradeElements; window.componentHandler = componentHandler; window['componentHandler'] = componentHandler; window.addEventListener('load', function() { 'use strict'; /** * Performs a "Cutting the mustard" test. If the browser supports the features * tested, adds a mdl-js class to the element. It then upgrades all MDL * components requiring JavaScript. */ if ('classList' in document.createElement('div') && 'querySelector' in document && 'addEventListener' in window && Array.prototype.forEach) { document.documentElement.classList.add('mdl-js'); componentHandler.upgradeAllRegistered(); } else { /** * Dummy function to avoid JS errors. */ componentHandler.upgradeElement = function() {}; /** * Dummy function to avoid JS errors. */ componentHandler.register = function() {}; } }); // Source: https://github.com/darius/requestAnimationFrame/blob/master/requestAnimationFrame.js // Adapted from https://gist.github.com/paulirish/1579671 which derived from // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating // requestAnimationFrame polyfill by Erik Möller. // Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon // MIT license if (!Date.now) { /** * Date.now polyfill. * @return {number} the current Date */ Date.now = function () { return new Date().getTime(); }; Date['now'] = Date.now; } var vendors = [ 'webkit', 'moz' ]; for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { var vp = vendors[i]; window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']; window['requestAnimationFrame'] = window.requestAnimationFrame; window['cancelAnimationFrame'] = window.cancelAnimationFrame; } if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { var lastTime = 0; /** * requestAnimationFrame polyfill. * @param {!Function} callback the callback function. */ window.requestAnimationFrame = function (callback) { var now = Date.now(); var nextTime = Math.max(lastTime + 16, now); return setTimeout(function () { callback(lastTime = nextTime); }, nextTime - now); }; window.cancelAnimationFrame = clearTimeout; window['requestAnimationFrame'] = window.requestAnimationFrame; window['cancelAnimationFrame'] = window.cancelAnimationFrame; } /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Button MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @param {HTMLElement} element The element that will be upgraded. */ var MaterialButton = function MaterialButton(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialButton'] = MaterialButton; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialButton.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialButton.prototype.CssClasses_ = { RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_CONTAINER: 'mdl-button__ripple-container', RIPPLE: 'mdl-ripple' }; /** * Handle blur of element. * * @param {Event} event The event that fired. * @private */ MaterialButton.prototype.blurHandler_ = function (event) { if (event) { this.element_.blur(); } }; // Public methods. /** * Disable button. * * @public */ MaterialButton.prototype.disable = function () { this.element_.disabled = true; }; MaterialButton.prototype['disable'] = MaterialButton.prototype.disable; /** * Enable button. * * @public */ MaterialButton.prototype.enable = function () { this.element_.disabled = false; }; MaterialButton.prototype['enable'] = MaterialButton.prototype.enable; /** * Initialize element. */ MaterialButton.prototype.init = function () { if (this.element_) { if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { var rippleContainer = document.createElement('span'); rippleContainer.classList.add(this.CssClasses_.RIPPLE_CONTAINER); this.rippleElement_ = document.createElement('span'); this.rippleElement_.classList.add(this.CssClasses_.RIPPLE); rippleContainer.appendChild(this.rippleElement_); this.boundRippleBlurHandler = this.blurHandler_.bind(this); this.rippleElement_.addEventListener('mouseup', this.boundRippleBlurHandler); this.element_.appendChild(rippleContainer); } this.boundButtonBlurHandler = this.blurHandler_.bind(this); this.element_.addEventListener('mouseup', this.boundButtonBlurHandler); this.element_.addEventListener('mouseleave', this.boundButtonBlurHandler); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialButton, classAsString: 'MaterialButton', cssClass: 'mdl-js-button', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Checkbox MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialCheckbox = function MaterialCheckbox(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialCheckbox'] = MaterialCheckbox; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialCheckbox.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialCheckbox.prototype.CssClasses_ = { INPUT: 'mdl-checkbox__input', BOX_OUTLINE: 'mdl-checkbox__box-outline', FOCUS_HELPER: 'mdl-checkbox__focus-helper', TICK_OUTLINE: 'mdl-checkbox__tick-outline', RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', RIPPLE_CONTAINER: 'mdl-checkbox__ripple-container', RIPPLE_CENTER: 'mdl-ripple--center', RIPPLE: 'mdl-ripple', IS_FOCUSED: 'is-focused', IS_DISABLED: 'is-disabled', IS_CHECKED: 'is-checked', IS_UPGRADED: 'is-upgraded' }; /** * Handle change of state. * * @param {Event} event The event that fired. * @private */ MaterialCheckbox.prototype.onChange_ = function (event) { this.updateClasses_(); }; /** * Handle focus of element. * * @param {Event} event The event that fired. * @private */ MaterialCheckbox.prototype.onFocus_ = function (event) { this.element_.classList.add(this.CssClasses_.IS_FOCUSED); }; /** * Handle lost focus of element. * * @param {Event} event The event that fired. * @private */ MaterialCheckbox.prototype.onBlur_ = function (event) { this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); }; /** * Handle mouseup. * * @param {Event} event The event that fired. * @private */ MaterialCheckbox.prototype.onMouseUp_ = function (event) { this.blur_(); }; /** * Handle class updates. * * @private */ MaterialCheckbox.prototype.updateClasses_ = function () { this.checkDisabled(); this.checkToggleState(); }; /** * Add blur. * * @private */ MaterialCheckbox.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.inputElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); }; // Public methods. /** * Check the inputs toggle state and update display. * * @public */ MaterialCheckbox.prototype.checkToggleState = function () { if (this.inputElement_.checked) { this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; MaterialCheckbox.prototype['checkToggleState'] = MaterialCheckbox.prototype.checkToggleState; /** * Check the inputs disabled state and update display. * * @public */ MaterialCheckbox.prototype.checkDisabled = function () { if (this.inputElement_.disabled) { this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; MaterialCheckbox.prototype['checkDisabled'] = MaterialCheckbox.prototype.checkDisabled; /** * Disable checkbox. * * @public */ MaterialCheckbox.prototype.disable = function () { this.inputElement_.disabled = true; this.updateClasses_(); }; MaterialCheckbox.prototype['disable'] = MaterialCheckbox.prototype.disable; /** * Enable checkbox. * * @public */ MaterialCheckbox.prototype.enable = function () { this.inputElement_.disabled = false; this.updateClasses_(); }; MaterialCheckbox.prototype['enable'] = MaterialCheckbox.prototype.enable; /** * Check checkbox. * * @public */ MaterialCheckbox.prototype.check = function () { this.inputElement_.checked = true; this.updateClasses_(); }; MaterialCheckbox.prototype['check'] = MaterialCheckbox.prototype.check; /** * Uncheck checkbox. * * @public */ MaterialCheckbox.prototype.uncheck = function () { this.inputElement_.checked = false; this.updateClasses_(); }; MaterialCheckbox.prototype['uncheck'] = MaterialCheckbox.prototype.uncheck; /** * Initialize element. */ MaterialCheckbox.prototype.init = function () { if (this.element_) { this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); var boxOutline = document.createElement('span'); boxOutline.classList.add(this.CssClasses_.BOX_OUTLINE); var tickContainer = document.createElement('span'); tickContainer.classList.add(this.CssClasses_.FOCUS_HELPER); var tickOutline = document.createElement('span'); tickOutline.classList.add(this.CssClasses_.TICK_OUTLINE); boxOutline.appendChild(tickOutline); this.element_.appendChild(tickContainer); this.element_.appendChild(boxOutline); if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); this.rippleContainerElement_ = document.createElement('span'); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_EFFECT); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER); this.boundRippleMouseUp = this.onMouseUp_.bind(this); this.rippleContainerElement_.addEventListener('mouseup', this.boundRippleMouseUp); var ripple = document.createElement('span'); ripple.classList.add(this.CssClasses_.RIPPLE); this.rippleContainerElement_.appendChild(ripple); this.element_.appendChild(this.rippleContainerElement_); } this.boundInputOnChange = this.onChange_.bind(this); this.boundInputOnFocus = this.onFocus_.bind(this); this.boundInputOnBlur = this.onBlur_.bind(this); this.boundElementMouseUp = this.onMouseUp_.bind(this); this.inputElement_.addEventListener('change', this.boundInputOnChange); this.inputElement_.addEventListener('focus', this.boundInputOnFocus); this.inputElement_.addEventListener('blur', this.boundInputOnBlur); this.element_.addEventListener('mouseup', this.boundElementMouseUp); this.updateClasses_(); this.element_.classList.add(this.CssClasses_.IS_UPGRADED); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialCheckbox, classAsString: 'MaterialCheckbox', cssClass: 'mdl-js-checkbox', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for icon toggle MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialIconToggle = function MaterialIconToggle(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialIconToggle'] = MaterialIconToggle; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialIconToggle.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialIconToggle.prototype.CssClasses_ = { INPUT: 'mdl-icon-toggle__input', JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', RIPPLE_CONTAINER: 'mdl-icon-toggle__ripple-container', RIPPLE_CENTER: 'mdl-ripple--center', RIPPLE: 'mdl-ripple', IS_FOCUSED: 'is-focused', IS_DISABLED: 'is-disabled', IS_CHECKED: 'is-checked' }; /** * Handle change of state. * * @param {Event} event The event that fired. * @private */ MaterialIconToggle.prototype.onChange_ = function (event) { this.updateClasses_(); }; /** * Handle focus of element. * * @param {Event} event The event that fired. * @private */ MaterialIconToggle.prototype.onFocus_ = function (event) { this.element_.classList.add(this.CssClasses_.IS_FOCUSED); }; /** * Handle lost focus of element. * * @param {Event} event The event that fired. * @private */ MaterialIconToggle.prototype.onBlur_ = function (event) { this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); }; /** * Handle mouseup. * * @param {Event} event The event that fired. * @private */ MaterialIconToggle.prototype.onMouseUp_ = function (event) { this.blur_(); }; /** * Handle class updates. * * @private */ MaterialIconToggle.prototype.updateClasses_ = function () { this.checkDisabled(); this.checkToggleState(); }; /** * Add blur. * * @private */ MaterialIconToggle.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.inputElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); }; // Public methods. /** * Check the inputs toggle state and update display. * * @public */ MaterialIconToggle.prototype.checkToggleState = function () { if (this.inputElement_.checked) { this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; MaterialIconToggle.prototype['checkToggleState'] = MaterialIconToggle.prototype.checkToggleState; /** * Check the inputs disabled state and update display. * * @public */ MaterialIconToggle.prototype.checkDisabled = function () { if (this.inputElement_.disabled) { this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; MaterialIconToggle.prototype['checkDisabled'] = MaterialIconToggle.prototype.checkDisabled; /** * Disable icon toggle. * * @public */ MaterialIconToggle.prototype.disable = function () { this.inputElement_.disabled = true; this.updateClasses_(); }; MaterialIconToggle.prototype['disable'] = MaterialIconToggle.prototype.disable; /** * Enable icon toggle. * * @public */ MaterialIconToggle.prototype.enable = function () { this.inputElement_.disabled = false; this.updateClasses_(); }; MaterialIconToggle.prototype['enable'] = MaterialIconToggle.prototype.enable; /** * Check icon toggle. * * @public */ MaterialIconToggle.prototype.check = function () { this.inputElement_.checked = true; this.updateClasses_(); }; MaterialIconToggle.prototype['check'] = MaterialIconToggle.prototype.check; /** * Uncheck icon toggle. * * @public */ MaterialIconToggle.prototype.uncheck = function () { this.inputElement_.checked = false; this.updateClasses_(); }; MaterialIconToggle.prototype['uncheck'] = MaterialIconToggle.prototype.uncheck; /** * Initialize element. */ MaterialIconToggle.prototype.init = function () { if (this.element_) { this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); if (this.element_.classList.contains(this.CssClasses_.JS_RIPPLE_EFFECT)) { this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); this.rippleContainerElement_ = document.createElement('span'); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER); this.rippleContainerElement_.classList.add(this.CssClasses_.JS_RIPPLE_EFFECT); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER); this.boundRippleMouseUp = this.onMouseUp_.bind(this); this.rippleContainerElement_.addEventListener('mouseup', this.boundRippleMouseUp); var ripple = document.createElement('span'); ripple.classList.add(this.CssClasses_.RIPPLE); this.rippleContainerElement_.appendChild(ripple); this.element_.appendChild(this.rippleContainerElement_); } this.boundInputOnChange = this.onChange_.bind(this); this.boundInputOnFocus = this.onFocus_.bind(this); this.boundInputOnBlur = this.onBlur_.bind(this); this.boundElementOnMouseUp = this.onMouseUp_.bind(this); this.inputElement_.addEventListener('change', this.boundInputOnChange); this.inputElement_.addEventListener('focus', this.boundInputOnFocus); this.inputElement_.addEventListener('blur', this.boundInputOnBlur); this.element_.addEventListener('mouseup', this.boundElementOnMouseUp); this.updateClasses_(); this.element_.classList.add('is-upgraded'); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialIconToggle, classAsString: 'MaterialIconToggle', cssClass: 'mdl-js-icon-toggle', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for dropdown MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialMenu = function MaterialMenu(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialMenu'] = MaterialMenu; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialMenu.prototype.Constant_ = { // Total duration of the menu animation. TRANSITION_DURATION_SECONDS: 0.3, // The fraction of the total duration we want to use for menu item animations. TRANSITION_DURATION_FRACTION: 0.8, // How long the menu stays open after choosing an option (so the user can see // the ripple). CLOSE_TIMEOUT: 150 }; /** * Keycodes, for code readability. * * @enum {number} * @private */ MaterialMenu.prototype.Keycodes_ = { ENTER: 13, ESCAPE: 27, SPACE: 32, UP_ARROW: 38, DOWN_ARROW: 40 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialMenu.prototype.CssClasses_ = { CONTAINER: 'mdl-menu__container', OUTLINE: 'mdl-menu__outline', ITEM: 'mdl-menu__item', ITEM_RIPPLE_CONTAINER: 'mdl-menu__item-ripple-container', RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', RIPPLE: 'mdl-ripple', // Statuses IS_UPGRADED: 'is-upgraded', IS_VISIBLE: 'is-visible', IS_ANIMATING: 'is-animating', // Alignment options BOTTOM_LEFT: 'mdl-menu--bottom-left', // This is the default. BOTTOM_RIGHT: 'mdl-menu--bottom-right', TOP_LEFT: 'mdl-menu--top-left', TOP_RIGHT: 'mdl-menu--top-right', UNALIGNED: 'mdl-menu--unaligned' }; /** * Initialize element. */ MaterialMenu.prototype.init = function () { if (this.element_) { // Create container for the menu. var container = document.createElement('div'); container.classList.add(this.CssClasses_.CONTAINER); this.element_.parentElement.insertBefore(container, this.element_); this.element_.parentElement.removeChild(this.element_); container.appendChild(this.element_); this.container_ = container; // Create outline for the menu (shadow and background). var outline = document.createElement('div'); outline.classList.add(this.CssClasses_.OUTLINE); this.outline_ = outline; container.insertBefore(outline, this.element_); // Find the "for" element and bind events to it. var forElId = this.element_.getAttribute('for') || this.element_.getAttribute('data-mdl-for'); var forEl = null; if (forElId) { forEl = document.getElementById(forElId); if (forEl) { this.forElement_ = forEl; forEl.addEventListener('click', this.handleForClick_.bind(this)); forEl.addEventListener('keydown', this.handleForKeyboardEvent_.bind(this)); } } var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM); this.boundItemKeydown_ = this.handleItemKeyboardEvent_.bind(this); this.boundItemClick_ = this.handleItemClick_.bind(this); for (var i = 0; i < items.length; i++) { // Add a listener to each menu item. items[i].addEventListener('click', this.boundItemClick_); // Add a tab index to each menu item. items[i].tabIndex = '-1'; // Add a keyboard listener to each menu item. items[i].addEventListener('keydown', this.boundItemKeydown_); } // Add ripple classes to each item, if the user has enabled ripples. if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); for (i = 0; i < items.length; i++) { var item = items[i]; var rippleContainer = document.createElement('span'); rippleContainer.classList.add(this.CssClasses_.ITEM_RIPPLE_CONTAINER); var ripple = document.createElement('span'); ripple.classList.add(this.CssClasses_.RIPPLE); rippleContainer.appendChild(ripple); item.appendChild(rippleContainer); item.classList.add(this.CssClasses_.RIPPLE_EFFECT); } } // Copy alignment classes to the container, so the outline can use them. if (this.element_.classList.contains(this.CssClasses_.BOTTOM_LEFT)) { this.outline_.classList.add(this.CssClasses_.BOTTOM_LEFT); } if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) { this.outline_.classList.add(this.CssClasses_.BOTTOM_RIGHT); } if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) { this.outline_.classList.add(this.CssClasses_.TOP_LEFT); } if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { this.outline_.classList.add(this.CssClasses_.TOP_RIGHT); } if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) { this.outline_.classList.add(this.CssClasses_.UNALIGNED); } container.classList.add(this.CssClasses_.IS_UPGRADED); } }; /** * Handles a click on the "for" element, by positioning the menu and then * toggling it. * * @param {Event} evt The event that fired. * @private */ MaterialMenu.prototype.handleForClick_ = function (evt) { if (this.element_ && this.forElement_) { var rect = this.forElement_.getBoundingClientRect(); var forRect = this.forElement_.parentElement.getBoundingClientRect(); if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) { } else if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) { // Position below the "for" element, aligned to its right. this.container_.style.right = forRect.right - rect.right + 'px'; this.container_.style.top = this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px'; } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) { // Position above the "for" element, aligned to its left. this.container_.style.left = this.forElement_.offsetLeft + 'px'; this.container_.style.bottom = forRect.bottom - rect.top + 'px'; } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { // Position above the "for" element, aligned to its right. this.container_.style.right = forRect.right - rect.right + 'px'; this.container_.style.bottom = forRect.bottom - rect.top + 'px'; } else { // Default: position below the "for" element, aligned to its left. this.container_.style.left = this.forElement_.offsetLeft + 'px'; this.container_.style.top = this.forElement_.offsetTop + this.forElement_.offsetHeight + 'px'; } } this.toggle(evt); }; /** * Handles a keyboard event on the "for" element. * * @param {Event} evt The event that fired. * @private */ MaterialMenu.prototype.handleForKeyboardEvent_ = function (evt) { if (this.element_ && this.container_ && this.forElement_) { var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM + ':not([disabled])'); if (items && items.length > 0 && this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) { if (evt.keyCode === this.Keycodes_.UP_ARROW) { evt.preventDefault(); items[items.length - 1].focus(); } else if (evt.keyCode === this.Keycodes_.DOWN_ARROW) { evt.preventDefault(); items[0].focus(); } } } }; /** * Handles a keyboard event on an item. * * @param {Event} evt The event that fired. * @private */ MaterialMenu.prototype.handleItemKeyboardEvent_ = function (evt) { if (this.element_ && this.container_) { var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM + ':not([disabled])'); if (items && items.length > 0 && this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) { var currentIndex = Array.prototype.slice.call(items).indexOf(evt.target); if (evt.keyCode === this.Keycodes_.UP_ARROW) { evt.preventDefault(); if (currentIndex > 0) { items[currentIndex - 1].focus(); } else { items[items.length - 1].focus(); } } else if (evt.keyCode === this.Keycodes_.DOWN_ARROW) { evt.preventDefault(); if (items.length > currentIndex + 1) { items[currentIndex + 1].focus(); } else { items[0].focus(); } } else if (evt.keyCode === this.Keycodes_.SPACE || evt.keyCode === this.Keycodes_.ENTER) { evt.preventDefault(); // Send mousedown and mouseup to trigger ripple. var e = new MouseEvent('mousedown'); evt.target.dispatchEvent(e); e = new MouseEvent('mouseup'); evt.target.dispatchEvent(e); // Send click. evt.target.click(); } else if (evt.keyCode === this.Keycodes_.ESCAPE) { evt.preventDefault(); this.hide(); } } } }; /** * Handles a click event on an item. * * @param {Event} evt The event that fired. * @private */ MaterialMenu.prototype.handleItemClick_ = function (evt) { if (evt.target.hasAttribute('disabled')) { evt.stopPropagation(); } else { // Wait some time before closing menu, so the user can see the ripple. this.closing_ = true; window.setTimeout(function (evt) { this.hide(); this.closing_ = false; }.bind(this), this.Constant_.CLOSE_TIMEOUT); } }; /** * Calculates the initial clip (for opening the menu) or final clip (for closing * it), and applies it. This allows us to animate from or to the correct point, * that is, the point it's aligned to in the "for" element. * * @param {number} height Height of the clip rectangle * @param {number} width Width of the clip rectangle * @private */ MaterialMenu.prototype.applyClip_ = function (height, width) { if (this.element_.classList.contains(this.CssClasses_.UNALIGNED)) { // Do not clip. this.element_.style.clip = ''; } else if (this.element_.classList.contains(this.CssClasses_.BOTTOM_RIGHT)) { // Clip to the top right corner of the menu. this.element_.style.clip = 'rect(0 ' + width + 'px ' + '0 ' + width + 'px)'; } else if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT)) { // Clip to the bottom left corner of the menu. this.element_.style.clip = 'rect(' + height + 'px 0 ' + height + 'px 0)'; } else if (this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { // Clip to the bottom right corner of the menu. this.element_.style.clip = 'rect(' + height + 'px ' + width + 'px ' + height + 'px ' + width + 'px)'; } else { // Default: do not clip (same as clipping to the top left corner). this.element_.style.clip = ''; } }; /** * Cleanup function to remove animation listeners. * * @param {Event} evt * @private */ MaterialMenu.prototype.removeAnimationEndListener_ = function (evt) { evt.target.classList.remove(MaterialMenu.prototype.CssClasses_.IS_ANIMATING); }; /** * Adds an event listener to clean up after the animation ends. * * @private */ MaterialMenu.prototype.addAnimationEndListener_ = function () { this.element_.addEventListener('transitionend', this.removeAnimationEndListener_); this.element_.addEventListener('webkitTransitionEnd', this.removeAnimationEndListener_); }; /** * Displays the menu. * * @public */ MaterialMenu.prototype.show = function (evt) { if (this.element_ && this.container_ && this.outline_) { // Measure the inner element. var height = this.element_.getBoundingClientRect().height; var width = this.element_.getBoundingClientRect().width; // Apply the inner element's size to the container and outline. this.container_.style.width = width + 'px'; this.container_.style.height = height + 'px'; this.outline_.style.width = width + 'px'; this.outline_.style.height = height + 'px'; var transitionDuration = this.Constant_.TRANSITION_DURATION_SECONDS * this.Constant_.TRANSITION_DURATION_FRACTION; // Calculate transition delays for individual menu items, so that they fade // in one at a time. var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM); for (var i = 0; i < items.length; i++) { var itemDelay = null; if (this.element_.classList.contains(this.CssClasses_.TOP_LEFT) || this.element_.classList.contains(this.CssClasses_.TOP_RIGHT)) { itemDelay = (height - items[i].offsetTop - items[i].offsetHeight) / height * transitionDuration + 's'; } else { itemDelay = items[i].offsetTop / height * transitionDuration + 's'; } items[i].style.transitionDelay = itemDelay; } // Apply the initial clip to the text before we start animating. this.applyClip_(height, width); // Wait for the next frame, turn on animation, and apply the final clip. // Also make it visible. This triggers the transitions. window.requestAnimationFrame(function () { this.element_.classList.add(this.CssClasses_.IS_ANIMATING); this.element_.style.clip = 'rect(0 ' + width + 'px ' + height + 'px 0)'; this.container_.classList.add(this.CssClasses_.IS_VISIBLE); }.bind(this)); // Clean up after the animation is complete. this.addAnimationEndListener_(); // Add a click listener to the document, to close the menu. var callback = function (e) { // Check to see if the document is processing the same event that // displayed the menu in the first place. If so, do nothing. // Also check to see if the menu is in the process of closing itself, and // do nothing in that case. // Also check if the clicked element is a menu item // if so, do nothing. if (e !== evt && !this.closing_ && e.target.parentNode !== this.element_) { document.removeEventListener('click', callback); this.hide(); } }.bind(this); document.addEventListener('click', callback); } }; MaterialMenu.prototype['show'] = MaterialMenu.prototype.show; /** * Hides the menu. * * @public */ MaterialMenu.prototype.hide = function () { if (this.element_ && this.container_ && this.outline_) { var items = this.element_.querySelectorAll('.' + this.CssClasses_.ITEM); // Remove all transition delays; menu items fade out concurrently. for (var i = 0; i < items.length; i++) { items[i].style.removeProperty('transition-delay'); } // Measure the inner element. var rect = this.element_.getBoundingClientRect(); var height = rect.height; var width = rect.width; // Turn on animation, and apply the final clip. Also make invisible. // This triggers the transitions. this.element_.classList.add(this.CssClasses_.IS_ANIMATING); this.applyClip_(height, width); this.container_.classList.remove(this.CssClasses_.IS_VISIBLE); // Clean up after the animation is complete. this.addAnimationEndListener_(); } }; MaterialMenu.prototype['hide'] = MaterialMenu.prototype.hide; /** * Displays or hides the menu, depending on current state. * * @public */ MaterialMenu.prototype.toggle = function (evt) { if (this.container_.classList.contains(this.CssClasses_.IS_VISIBLE)) { this.hide(); } else { this.show(evt); } }; MaterialMenu.prototype['toggle'] = MaterialMenu.prototype.toggle; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialMenu, classAsString: 'MaterialMenu', cssClass: 'mdl-js-menu', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Progress MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialProgress = function MaterialProgress(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialProgress'] = MaterialProgress; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialProgress.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialProgress.prototype.CssClasses_ = { INDETERMINATE_CLASS: 'mdl-progress__indeterminate' }; /** * Set the current progress of the progressbar. * * @param {number} p Percentage of the progress (0-100) * @public */ MaterialProgress.prototype.setProgress = function (p) { if (this.element_.classList.contains(this.CssClasses_.INDETERMINATE_CLASS)) { return; } this.progressbar_.style.width = p + '%'; }; MaterialProgress.prototype['setProgress'] = MaterialProgress.prototype.setProgress; /** * Set the current progress of the buffer. * * @param {number} p Percentage of the buffer (0-100) * @public */ MaterialProgress.prototype.setBuffer = function (p) { this.bufferbar_.style.width = p + '%'; this.auxbar_.style.width = 100 - p + '%'; }; MaterialProgress.prototype['setBuffer'] = MaterialProgress.prototype.setBuffer; /** * Initialize element. */ MaterialProgress.prototype.init = function () { if (this.element_) { var el = document.createElement('div'); el.className = 'progressbar bar bar1'; this.element_.appendChild(el); this.progressbar_ = el; el = document.createElement('div'); el.className = 'bufferbar bar bar2'; this.element_.appendChild(el); this.bufferbar_ = el; el = document.createElement('div'); el.className = 'auxbar bar bar3'; this.element_.appendChild(el); this.auxbar_ = el; this.progressbar_.style.width = '0%'; this.bufferbar_.style.width = '100%'; this.auxbar_.style.width = '0%'; this.element_.classList.add('is-upgraded'); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialProgress, classAsString: 'MaterialProgress', cssClass: 'mdl-js-progress', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Radio MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialRadio = function MaterialRadio(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialRadio'] = MaterialRadio; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialRadio.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialRadio.prototype.CssClasses_ = { IS_FOCUSED: 'is-focused', IS_DISABLED: 'is-disabled', IS_CHECKED: 'is-checked', IS_UPGRADED: 'is-upgraded', JS_RADIO: 'mdl-js-radio', RADIO_BTN: 'mdl-radio__button', RADIO_OUTER_CIRCLE: 'mdl-radio__outer-circle', RADIO_INNER_CIRCLE: 'mdl-radio__inner-circle', RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', RIPPLE_CONTAINER: 'mdl-radio__ripple-container', RIPPLE_CENTER: 'mdl-ripple--center', RIPPLE: 'mdl-ripple' }; /** * Handle change of state. * * @param {Event} event The event that fired. * @private */ MaterialRadio.prototype.onChange_ = function (event) { // Since other radio buttons don't get change events, we need to look for // them to update their classes. var radios = document.getElementsByClassName(this.CssClasses_.JS_RADIO); for (var i = 0; i < radios.length; i++) { var button = radios[i].querySelector('.' + this.CssClasses_.RADIO_BTN); // Different name == different group, so no point updating those. if (button.getAttribute('name') === this.btnElement_.getAttribute('name')) { if (typeof radios[i]['MaterialRadio'] !== 'undefined') { radios[i]['MaterialRadio'].updateClasses_(); } } } }; /** * Handle focus. * * @param {Event} event The event that fired. * @private */ MaterialRadio.prototype.onFocus_ = function (event) { this.element_.classList.add(this.CssClasses_.IS_FOCUSED); }; /** * Handle lost focus. * * @param {Event} event The event that fired. * @private */ MaterialRadio.prototype.onBlur_ = function (event) { this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); }; /** * Handle mouseup. * * @param {Event} event The event that fired. * @private */ MaterialRadio.prototype.onMouseup_ = function (event) { this.blur_(); }; /** * Update classes. * * @private */ MaterialRadio.prototype.updateClasses_ = function () { this.checkDisabled(); this.checkToggleState(); }; /** * Add blur. * * @private */ MaterialRadio.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.btnElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); }; // Public methods. /** * Check the components disabled state. * * @public */ MaterialRadio.prototype.checkDisabled = function () { if (this.btnElement_.disabled) { this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; MaterialRadio.prototype['checkDisabled'] = MaterialRadio.prototype.checkDisabled; /** * Check the components toggled state. * * @public */ MaterialRadio.prototype.checkToggleState = function () { if (this.btnElement_.checked) { this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; MaterialRadio.prototype['checkToggleState'] = MaterialRadio.prototype.checkToggleState; /** * Disable radio. * * @public */ MaterialRadio.prototype.disable = function () { this.btnElement_.disabled = true; this.updateClasses_(); }; MaterialRadio.prototype['disable'] = MaterialRadio.prototype.disable; /** * Enable radio. * * @public */ MaterialRadio.prototype.enable = function () { this.btnElement_.disabled = false; this.updateClasses_(); }; MaterialRadio.prototype['enable'] = MaterialRadio.prototype.enable; /** * Check radio. * * @public */ MaterialRadio.prototype.check = function () { this.btnElement_.checked = true; this.onChange_(null); }; MaterialRadio.prototype['check'] = MaterialRadio.prototype.check; /** * Uncheck radio. * * @public */ MaterialRadio.prototype.uncheck = function () { this.btnElement_.checked = false; this.onChange_(null); }; MaterialRadio.prototype['uncheck'] = MaterialRadio.prototype.uncheck; /** * Initialize element. */ MaterialRadio.prototype.init = function () { if (this.element_) { this.btnElement_ = this.element_.querySelector('.' + this.CssClasses_.RADIO_BTN); this.boundChangeHandler_ = this.onChange_.bind(this); this.boundFocusHandler_ = this.onChange_.bind(this); this.boundBlurHandler_ = this.onBlur_.bind(this); this.boundMouseUpHandler_ = this.onMouseup_.bind(this); var outerCircle = document.createElement('span'); outerCircle.classList.add(this.CssClasses_.RADIO_OUTER_CIRCLE); var innerCircle = document.createElement('span'); innerCircle.classList.add(this.CssClasses_.RADIO_INNER_CIRCLE); this.element_.appendChild(outerCircle); this.element_.appendChild(innerCircle); var rippleContainer; if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); rippleContainer = document.createElement('span'); rippleContainer.classList.add(this.CssClasses_.RIPPLE_CONTAINER); rippleContainer.classList.add(this.CssClasses_.RIPPLE_EFFECT); rippleContainer.classList.add(this.CssClasses_.RIPPLE_CENTER); rippleContainer.addEventListener('mouseup', this.boundMouseUpHandler_); var ripple = document.createElement('span'); ripple.classList.add(this.CssClasses_.RIPPLE); rippleContainer.appendChild(ripple); this.element_.appendChild(rippleContainer); } this.btnElement_.addEventListener('change', this.boundChangeHandler_); this.btnElement_.addEventListener('focus', this.boundFocusHandler_); this.btnElement_.addEventListener('blur', this.boundBlurHandler_); this.element_.addEventListener('mouseup', this.boundMouseUpHandler_); this.updateClasses_(); this.element_.classList.add(this.CssClasses_.IS_UPGRADED); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialRadio, classAsString: 'MaterialRadio', cssClass: 'mdl-js-radio', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Slider MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialSlider = function MaterialSlider(element) { this.element_ = element; // Browser feature detection. this.isIE_ = window.navigator.msPointerEnabled; // Initialize instance. this.init(); }; window['MaterialSlider'] = MaterialSlider; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialSlider.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialSlider.prototype.CssClasses_ = { IE_CONTAINER: 'mdl-slider__ie-container', SLIDER_CONTAINER: 'mdl-slider__container', BACKGROUND_FLEX: 'mdl-slider__background-flex', BACKGROUND_LOWER: 'mdl-slider__background-lower', BACKGROUND_UPPER: 'mdl-slider__background-upper', IS_LOWEST_VALUE: 'is-lowest-value', IS_UPGRADED: 'is-upgraded' }; /** * Handle input on element. * * @param {Event} event The event that fired. * @private */ MaterialSlider.prototype.onInput_ = function (event) { this.updateValueStyles_(); }; /** * Handle change on element. * * @param {Event} event The event that fired. * @private */ MaterialSlider.prototype.onChange_ = function (event) { this.updateValueStyles_(); }; /** * Handle mouseup on element. * * @param {Event} event The event that fired. * @private */ MaterialSlider.prototype.onMouseUp_ = function (event) { event.target.blur(); }; /** * Handle mousedown on container element. * This handler is purpose is to not require the use to click * exactly on the 2px slider element, as FireFox seems to be very * strict about this. * * @param {Event} event The event that fired. * @private * @suppress {missingProperties} */ MaterialSlider.prototype.onContainerMouseDown_ = function (event) { // If this click is not on the parent element (but rather some child) // ignore. It may still bubble up. if (event.target !== this.element_.parentElement) { return; } // Discard the original event and create a new event that // is on the slider element. event.preventDefault(); var newEvent = new MouseEvent('mousedown', { target: event.target, buttons: event.buttons, clientX: event.clientX, clientY: this.element_.getBoundingClientRect().y }); this.element_.dispatchEvent(newEvent); }; /** * Handle updating of values. * * @private */ MaterialSlider.prototype.updateValueStyles_ = function () { // Calculate and apply percentages to div structure behind slider. var fraction = (this.element_.value - this.element_.min) / (this.element_.max - this.element_.min); if (fraction === 0) { this.element_.classList.add(this.CssClasses_.IS_LOWEST_VALUE); } else { this.element_.classList.remove(this.CssClasses_.IS_LOWEST_VALUE); } if (!this.isIE_) { this.backgroundLower_.style.flex = fraction; this.backgroundLower_.style.webkitFlex = fraction; this.backgroundUpper_.style.flex = 1 - fraction; this.backgroundUpper_.style.webkitFlex = 1 - fraction; } }; // Public methods. /** * Disable slider. * * @public */ MaterialSlider.prototype.disable = function () { this.element_.disabled = true; }; MaterialSlider.prototype['disable'] = MaterialSlider.prototype.disable; /** * Enable slider. * * @public */ MaterialSlider.prototype.enable = function () { this.element_.disabled = false; }; MaterialSlider.prototype['enable'] = MaterialSlider.prototype.enable; /** * Update slider value. * * @param {number} value The value to which to set the control (optional). * @public */ MaterialSlider.prototype.change = function (value) { if (typeof value !== 'undefined') { this.element_.value = value; } this.updateValueStyles_(); }; MaterialSlider.prototype['change'] = MaterialSlider.prototype.change; /** * Initialize element. */ MaterialSlider.prototype.init = function () { if (this.element_) { if (this.isIE_) { // Since we need to specify a very large height in IE due to // implementation limitations, we add a parent here that trims it down to // a reasonable size. var containerIE = document.createElement('div'); containerIE.classList.add(this.CssClasses_.IE_CONTAINER); this.element_.parentElement.insertBefore(containerIE, this.element_); this.element_.parentElement.removeChild(this.element_); containerIE.appendChild(this.element_); } else { // For non-IE browsers, we need a div structure that sits behind the // slider and allows us to style the left and right sides of it with // different colors. var container = document.createElement('div'); container.classList.add(this.CssClasses_.SLIDER_CONTAINER); this.element_.parentElement.insertBefore(container, this.element_); this.element_.parentElement.removeChild(this.element_); container.appendChild(this.element_); var backgroundFlex = document.createElement('div'); backgroundFlex.classList.add(this.CssClasses_.BACKGROUND_FLEX); container.appendChild(backgroundFlex); this.backgroundLower_ = document.createElement('div'); this.backgroundLower_.classList.add(this.CssClasses_.BACKGROUND_LOWER); backgroundFlex.appendChild(this.backgroundLower_); this.backgroundUpper_ = document.createElement('div'); this.backgroundUpper_.classList.add(this.CssClasses_.BACKGROUND_UPPER); backgroundFlex.appendChild(this.backgroundUpper_); } this.boundInputHandler = this.onInput_.bind(this); this.boundChangeHandler = this.onChange_.bind(this); this.boundMouseUpHandler = this.onMouseUp_.bind(this); this.boundContainerMouseDownHandler = this.onContainerMouseDown_.bind(this); this.element_.addEventListener('input', this.boundInputHandler); this.element_.addEventListener('change', this.boundChangeHandler); this.element_.addEventListener('mouseup', this.boundMouseUpHandler); this.element_.parentElement.addEventListener('mousedown', this.boundContainerMouseDownHandler); this.updateValueStyles_(); this.element_.classList.add(this.CssClasses_.IS_UPGRADED); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialSlider, classAsString: 'MaterialSlider', cssClass: 'mdl-js-slider', widget: true }); /** * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Snackbar MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialSnackbar = function MaterialSnackbar(element) { this.element_ = element; this.textElement_ = this.element_.querySelector('.' + this.cssClasses_.MESSAGE); this.actionElement_ = this.element_.querySelector('.' + this.cssClasses_.ACTION); if (!this.textElement_) { throw new Error('There must be a message element for a snackbar.'); } if (!this.actionElement_) { throw new Error('There must be an action element for a snackbar.'); } this.active = false; this.actionHandler_ = undefined; this.message_ = undefined; this.actionText_ = undefined; this.queuedNotifications_ = []; this.setActionHidden_(true); }; window['MaterialSnackbar'] = MaterialSnackbar; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialSnackbar.prototype.Constant_ = { // The duration of the snackbar show/hide animation, in ms. ANIMATION_LENGTH: 250 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialSnackbar.prototype.cssClasses_ = { SNACKBAR: 'mdl-snackbar', MESSAGE: 'mdl-snackbar__text', ACTION: 'mdl-snackbar__action', ACTIVE: 'mdl-snackbar--active' }; /** * Display the snackbar. * * @private */ MaterialSnackbar.prototype.displaySnackbar_ = function () { this.element_.setAttribute('aria-hidden', 'true'); if (this.actionHandler_) { this.actionElement_.textContent = this.actionText_; this.actionElement_.addEventListener('click', this.actionHandler_); this.setActionHidden_(false); } this.textElement_.textContent = this.message_; this.element_.classList.add(this.cssClasses_.ACTIVE); this.element_.setAttribute('aria-hidden', 'false'); setTimeout(this.cleanup_.bind(this), this.timeout_); }; /** * Show the snackbar. * * @param {Object} data The data for the notification. * @public */ MaterialSnackbar.prototype.showSnackbar = function (data) { if (data === undefined) { throw new Error('Please provide a data object with at least a message to display.'); } if (data['message'] === undefined) { throw new Error('Please provide a message to be displayed.'); } if (data['actionHandler'] && !data['actionText']) { throw new Error('Please provide action text with the handler.'); } if (this.active) { this.queuedNotifications_.push(data); } else { this.active = true; this.message_ = data['message']; if (data['timeout']) { this.timeout_ = data['timeout']; } else { this.timeout_ = 2750; } if (data['actionHandler']) { this.actionHandler_ = data['actionHandler']; } if (data['actionText']) { this.actionText_ = data['actionText']; } this.displaySnackbar_(); } }; MaterialSnackbar.prototype['showSnackbar'] = MaterialSnackbar.prototype.showSnackbar; /** * Check if the queue has items within it. * If it does, display the next entry. * * @private */ MaterialSnackbar.prototype.checkQueue_ = function () { if (this.queuedNotifications_.length > 0) { this.showSnackbar(this.queuedNotifications_.shift()); } }; /** * Cleanup the snackbar event listeners and accessiblity attributes. * * @private */ MaterialSnackbar.prototype.cleanup_ = function () { this.element_.classList.remove(this.cssClasses_.ACTIVE); setTimeout(function () { this.element_.setAttribute('aria-hidden', 'true'); this.textElement_.textContent = ''; if (!Boolean(this.actionElement_.getAttribute('aria-hidden'))) { this.setActionHidden_(true); this.actionElement_.textContent = ''; this.actionElement_.removeEventListener('click', this.actionHandler_); } this.actionHandler_ = undefined; this.message_ = undefined; this.actionText_ = undefined; this.active = false; this.checkQueue_(); }.bind(this), this.Constant_.ANIMATION_LENGTH); }; /** * Set the action handler hidden state. * * @param {boolean} value * @private */ MaterialSnackbar.prototype.setActionHidden_ = function (value) { if (value) { this.actionElement_.setAttribute('aria-hidden', 'true'); } else { this.actionElement_.removeAttribute('aria-hidden'); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialSnackbar, classAsString: 'MaterialSnackbar', cssClass: 'mdl-js-snackbar', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Spinner MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @param {HTMLElement} element The element that will be upgraded. * @constructor */ var MaterialSpinner = function MaterialSpinner(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialSpinner'] = MaterialSpinner; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialSpinner.prototype.Constant_ = { MDL_SPINNER_LAYER_COUNT: 4 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialSpinner.prototype.CssClasses_ = { MDL_SPINNER_LAYER: 'mdl-spinner__layer', MDL_SPINNER_CIRCLE_CLIPPER: 'mdl-spinner__circle-clipper', MDL_SPINNER_CIRCLE: 'mdl-spinner__circle', MDL_SPINNER_GAP_PATCH: 'mdl-spinner__gap-patch', MDL_SPINNER_LEFT: 'mdl-spinner__left', MDL_SPINNER_RIGHT: 'mdl-spinner__right' }; /** * Auxiliary method to create a spinner layer. * * @param {number} index Index of the layer to be created. * @public */ MaterialSpinner.prototype.createLayer = function (index) { var layer = document.createElement('div'); layer.classList.add(this.CssClasses_.MDL_SPINNER_LAYER); layer.classList.add(this.CssClasses_.MDL_SPINNER_LAYER + '-' + index); var leftClipper = document.createElement('div'); leftClipper.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE_CLIPPER); leftClipper.classList.add(this.CssClasses_.MDL_SPINNER_LEFT); var gapPatch = document.createElement('div'); gapPatch.classList.add(this.CssClasses_.MDL_SPINNER_GAP_PATCH); var rightClipper = document.createElement('div'); rightClipper.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE_CLIPPER); rightClipper.classList.add(this.CssClasses_.MDL_SPINNER_RIGHT); var circleOwners = [ leftClipper, gapPatch, rightClipper ]; for (var i = 0; i < circleOwners.length; i++) { var circle = document.createElement('div'); circle.classList.add(this.CssClasses_.MDL_SPINNER_CIRCLE); circleOwners[i].appendChild(circle); } layer.appendChild(leftClipper); layer.appendChild(gapPatch); layer.appendChild(rightClipper); this.element_.appendChild(layer); }; MaterialSpinner.prototype['createLayer'] = MaterialSpinner.prototype.createLayer; /** * Stops the spinner animation. * Public method for users who need to stop the spinner for any reason. * * @public */ MaterialSpinner.prototype.stop = function () { this.element_.classList.remove('is-active'); }; MaterialSpinner.prototype['stop'] = MaterialSpinner.prototype.stop; /** * Starts the spinner animation. * Public method for users who need to manually start the spinner for any reason * (instead of just adding the 'is-active' class to their markup). * * @public */ MaterialSpinner.prototype.start = function () { this.element_.classList.add('is-active'); }; MaterialSpinner.prototype['start'] = MaterialSpinner.prototype.start; /** * Initialize element. */ MaterialSpinner.prototype.init = function () { if (this.element_) { for (var i = 1; i <= this.Constant_.MDL_SPINNER_LAYER_COUNT; i++) { this.createLayer(i); } this.element_.classList.add('is-upgraded'); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialSpinner, classAsString: 'MaterialSpinner', cssClass: 'mdl-js-spinner', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Checkbox MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialSwitch = function MaterialSwitch(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialSwitch'] = MaterialSwitch; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialSwitch.prototype.Constant_ = { TINY_TIMEOUT: 0.001 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialSwitch.prototype.CssClasses_ = { INPUT: 'mdl-switch__input', TRACK: 'mdl-switch__track', THUMB: 'mdl-switch__thumb', FOCUS_HELPER: 'mdl-switch__focus-helper', RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', RIPPLE_CONTAINER: 'mdl-switch__ripple-container', RIPPLE_CENTER: 'mdl-ripple--center', RIPPLE: 'mdl-ripple', IS_FOCUSED: 'is-focused', IS_DISABLED: 'is-disabled', IS_CHECKED: 'is-checked' }; /** * Handle change of state. * * @param {Event} event The event that fired. * @private */ MaterialSwitch.prototype.onChange_ = function (event) { this.updateClasses_(); }; /** * Handle focus of element. * * @param {Event} event The event that fired. * @private */ MaterialSwitch.prototype.onFocus_ = function (event) { this.element_.classList.add(this.CssClasses_.IS_FOCUSED); }; /** * Handle lost focus of element. * * @param {Event} event The event that fired. * @private */ MaterialSwitch.prototype.onBlur_ = function (event) { this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); }; /** * Handle mouseup. * * @param {Event} event The event that fired. * @private */ MaterialSwitch.prototype.onMouseUp_ = function (event) { this.blur_(); }; /** * Handle class updates. * * @private */ MaterialSwitch.prototype.updateClasses_ = function () { this.checkDisabled(); this.checkToggleState(); }; /** * Add blur. * * @private */ MaterialSwitch.prototype.blur_ = function () { // TODO: figure out why there's a focus event being fired after our blur, // so that we can avoid this hack. window.setTimeout(function () { this.inputElement_.blur(); }.bind(this), this.Constant_.TINY_TIMEOUT); }; // Public methods. /** * Check the components disabled state. * * @public */ MaterialSwitch.prototype.checkDisabled = function () { if (this.inputElement_.disabled) { this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; MaterialSwitch.prototype['checkDisabled'] = MaterialSwitch.prototype.checkDisabled; /** * Check the components toggled state. * * @public */ MaterialSwitch.prototype.checkToggleState = function () { if (this.inputElement_.checked) { this.element_.classList.add(this.CssClasses_.IS_CHECKED); } else { this.element_.classList.remove(this.CssClasses_.IS_CHECKED); } }; MaterialSwitch.prototype['checkToggleState'] = MaterialSwitch.prototype.checkToggleState; /** * Disable switch. * * @public */ MaterialSwitch.prototype.disable = function () { this.inputElement_.disabled = true; this.updateClasses_(); }; MaterialSwitch.prototype['disable'] = MaterialSwitch.prototype.disable; /** * Enable switch. * * @public */ MaterialSwitch.prototype.enable = function () { this.inputElement_.disabled = false; this.updateClasses_(); }; MaterialSwitch.prototype['enable'] = MaterialSwitch.prototype.enable; /** * Activate switch. * * @public */ MaterialSwitch.prototype.on = function () { this.inputElement_.checked = true; this.updateClasses_(); }; MaterialSwitch.prototype['on'] = MaterialSwitch.prototype.on; /** * Deactivate switch. * * @public */ MaterialSwitch.prototype.off = function () { this.inputElement_.checked = false; this.updateClasses_(); }; MaterialSwitch.prototype['off'] = MaterialSwitch.prototype.off; /** * Initialize element. */ MaterialSwitch.prototype.init = function () { if (this.element_) { this.inputElement_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); var track = document.createElement('div'); track.classList.add(this.CssClasses_.TRACK); var thumb = document.createElement('div'); thumb.classList.add(this.CssClasses_.THUMB); var focusHelper = document.createElement('span'); focusHelper.classList.add(this.CssClasses_.FOCUS_HELPER); thumb.appendChild(focusHelper); this.element_.appendChild(track); this.element_.appendChild(thumb); this.boundMouseUpHandler = this.onMouseUp_.bind(this); if (this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT)) { this.element_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); this.rippleContainerElement_ = document.createElement('span'); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CONTAINER); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_EFFECT); this.rippleContainerElement_.classList.add(this.CssClasses_.RIPPLE_CENTER); this.rippleContainerElement_.addEventListener('mouseup', this.boundMouseUpHandler); var ripple = document.createElement('span'); ripple.classList.add(this.CssClasses_.RIPPLE); this.rippleContainerElement_.appendChild(ripple); this.element_.appendChild(this.rippleContainerElement_); } this.boundChangeHandler = this.onChange_.bind(this); this.boundFocusHandler = this.onFocus_.bind(this); this.boundBlurHandler = this.onBlur_.bind(this); this.inputElement_.addEventListener('change', this.boundChangeHandler); this.inputElement_.addEventListener('focus', this.boundFocusHandler); this.inputElement_.addEventListener('blur', this.boundBlurHandler); this.element_.addEventListener('mouseup', this.boundMouseUpHandler); this.updateClasses_(); this.element_.classList.add('is-upgraded'); } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialSwitch, classAsString: 'MaterialSwitch', cssClass: 'mdl-js-switch', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Tabs MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {Element} element The element that will be upgraded. */ var MaterialTabs = function MaterialTabs(element) { // Stores the HTML element. this.element_ = element; // Initialize instance. this.init(); }; window['MaterialTabs'] = MaterialTabs; /** * Store constants in one place so they can be updated easily. * * @enum {string} * @private */ MaterialTabs.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialTabs.prototype.CssClasses_ = { TAB_CLASS: 'mdl-tabs__tab', PANEL_CLASS: 'mdl-tabs__panel', ACTIVE_CLASS: 'is-active', UPGRADED_CLASS: 'is-upgraded', MDL_JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect', MDL_RIPPLE_CONTAINER: 'mdl-tabs__ripple-container', MDL_RIPPLE: 'mdl-ripple', MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events' }; /** * Handle clicks to a tabs component * * @private */ MaterialTabs.prototype.initTabs_ = function () { if (this.element_.classList.contains(this.CssClasses_.MDL_JS_RIPPLE_EFFECT)) { this.element_.classList.add(this.CssClasses_.MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS); } // Select element tabs, document panels this.tabs_ = this.element_.querySelectorAll('.' + this.CssClasses_.TAB_CLASS); this.panels_ = this.element_.querySelectorAll('.' + this.CssClasses_.PANEL_CLASS); // Create new tabs for each tab element for (var i = 0; i < this.tabs_.length; i++) { new MaterialTab(this.tabs_[i], this); } this.element_.classList.add(this.CssClasses_.UPGRADED_CLASS); }; /** * Reset tab state, dropping active classes * * @private */ MaterialTabs.prototype.resetTabState_ = function () { for (var k = 0; k < this.tabs_.length; k++) { this.tabs_[k].classList.remove(this.CssClasses_.ACTIVE_CLASS); } }; /** * Reset panel state, droping active classes * * @private */ MaterialTabs.prototype.resetPanelState_ = function () { for (var j = 0; j < this.panels_.length; j++) { this.panels_[j].classList.remove(this.CssClasses_.ACTIVE_CLASS); } }; /** * Initialize element. */ MaterialTabs.prototype.init = function () { if (this.element_) { this.initTabs_(); } }; /** * Constructor for an individual tab. * * @constructor * @param {Element} tab The HTML element for the tab. * @param {MaterialTabs} ctx The MaterialTabs object that owns the tab. */ function MaterialTab(tab, ctx) { if (tab) { if (ctx.element_.classList.contains(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT)) { var rippleContainer = document.createElement('span'); rippleContainer.classList.add(ctx.CssClasses_.MDL_RIPPLE_CONTAINER); rippleContainer.classList.add(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT); var ripple = document.createElement('span'); ripple.classList.add(ctx.CssClasses_.MDL_RIPPLE); rippleContainer.appendChild(ripple); tab.appendChild(rippleContainer); } tab.addEventListener('click', function (e) { if ((tab.getAttribute('href') !== null) && (tab.getAttribute('href').charAt(0) === '#')) { e.preventDefault(); var href = tab.href.split('#')[1]; var panel = ctx.element_.querySelector('#' + href); ctx.resetTabState_(); ctx.resetPanelState_(); tab.classList.add(ctx.CssClasses_.ACTIVE_CLASS); panel.classList.add(ctx.CssClasses_.ACTIVE_CLASS); } }); } } // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialTabs, classAsString: 'MaterialTabs', cssClass: 'mdl-js-tabs' }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Textfield MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialTextfield = function MaterialTextfield(element) { this.element_ = element; this.maxRows = this.Constant_.NO_MAX_ROWS; // Initialize instance. this.init(); }; window['MaterialTextfield'] = MaterialTextfield; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialTextfield.prototype.Constant_ = { NO_MAX_ROWS: -1, MAX_ROWS_ATTRIBUTE: 'maxrows' }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialTextfield.prototype.CssClasses_ = { LABEL: 'mdl-textfield__label', INPUT: 'mdl-textfield__input', IS_DIRTY: 'is-dirty', IS_FOCUSED: 'is-focused', IS_DISABLED: 'is-disabled', IS_INVALID: 'is-invalid', IS_UPGRADED: 'is-upgraded', HAS_PLACEHOLDER: 'has-placeholder' }; /** * Handle input being entered. * * @param {Event} event The event that fired. * @private */ MaterialTextfield.prototype.onKeyDown_ = function (event) { var currentRowCount = event.target.value.split('\n').length; if (event.keyCode === 13) { if (currentRowCount >= this.maxRows) { event.preventDefault(); } } }; /** * Handle focus. * * @param {Event} event The event that fired. * @private */ MaterialTextfield.prototype.onFocus_ = function (event) { this.element_.classList.add(this.CssClasses_.IS_FOCUSED); }; /** * Handle lost focus. * * @param {Event} event The event that fired. * @private */ MaterialTextfield.prototype.onBlur_ = function (event) { this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); }; /** * Handle reset event from out side. * * @param {Event} event The event that fired. * @private */ MaterialTextfield.prototype.onReset_ = function (event) { this.updateClasses_(); }; /** * Handle class updates. * * @private */ MaterialTextfield.prototype.updateClasses_ = function () { this.checkDisabled(); this.checkValidity(); this.checkDirty(); this.checkFocus(); }; // Public methods. /** * Check the disabled state and update field accordingly. * * @public */ MaterialTextfield.prototype.checkDisabled = function () { if (this.input_.disabled) { this.element_.classList.add(this.CssClasses_.IS_DISABLED); } else { this.element_.classList.remove(this.CssClasses_.IS_DISABLED); } }; MaterialTextfield.prototype['checkDisabled'] = MaterialTextfield.prototype.checkDisabled; /** * Check the focus state and update field accordingly. * * @public */ MaterialTextfield.prototype.checkFocus = function () { if (Boolean(this.element_.querySelector(':focus'))) { this.element_.classList.add(this.CssClasses_.IS_FOCUSED); } else { this.element_.classList.remove(this.CssClasses_.IS_FOCUSED); } }; MaterialTextfield.prototype['checkFocus'] = MaterialTextfield.prototype.checkFocus; /** * Check the validity state and update field accordingly. * * @public */ MaterialTextfield.prototype.checkValidity = function () { if (this.input_.validity) { if (this.input_.validity.valid) { this.element_.classList.remove(this.CssClasses_.IS_INVALID); } else { this.element_.classList.add(this.CssClasses_.IS_INVALID); } } }; MaterialTextfield.prototype['checkValidity'] = MaterialTextfield.prototype.checkValidity; /** * Check the dirty state and update field accordingly. * * @public */ MaterialTextfield.prototype.checkDirty = function () { if (this.input_.value && this.input_.value.length > 0) { this.element_.classList.add(this.CssClasses_.IS_DIRTY); } else { this.element_.classList.remove(this.CssClasses_.IS_DIRTY); } }; MaterialTextfield.prototype['checkDirty'] = MaterialTextfield.prototype.checkDirty; /** * Disable text field. * * @public */ MaterialTextfield.prototype.disable = function () { this.input_.disabled = true; this.updateClasses_(); }; MaterialTextfield.prototype['disable'] = MaterialTextfield.prototype.disable; /** * Enable text field. * * @public */ MaterialTextfield.prototype.enable = function () { this.input_.disabled = false; this.updateClasses_(); }; MaterialTextfield.prototype['enable'] = MaterialTextfield.prototype.enable; /** * Update text field value. * * @param {string} value The value to which to set the control (optional). * @public */ MaterialTextfield.prototype.change = function (value) { this.input_.value = value || ''; this.updateClasses_(); }; MaterialTextfield.prototype['change'] = MaterialTextfield.prototype.change; /** * Initialize element. */ MaterialTextfield.prototype.init = function () { if (this.element_) { this.label_ = this.element_.querySelector('.' + this.CssClasses_.LABEL); this.input_ = this.element_.querySelector('.' + this.CssClasses_.INPUT); if (this.input_) { if (this.input_.hasAttribute(this.Constant_.MAX_ROWS_ATTRIBUTE)) { this.maxRows = parseInt(this.input_.getAttribute(this.Constant_.MAX_ROWS_ATTRIBUTE), 10); if (isNaN(this.maxRows)) { this.maxRows = this.Constant_.NO_MAX_ROWS; } } if (this.input_.hasAttribute('placeholder')) { this.element_.classList.add(this.CssClasses_.HAS_PLACEHOLDER); } this.boundUpdateClassesHandler = this.updateClasses_.bind(this); this.boundFocusHandler = this.onFocus_.bind(this); this.boundBlurHandler = this.onBlur_.bind(this); this.boundResetHandler = this.onReset_.bind(this); this.input_.addEventListener('input', this.boundUpdateClassesHandler); this.input_.addEventListener('focus', this.boundFocusHandler); this.input_.addEventListener('blur', this.boundBlurHandler); this.input_.addEventListener('reset', this.boundResetHandler); if (this.maxRows !== this.Constant_.NO_MAX_ROWS) { // TODO: This should handle pasting multi line text. // Currently doesn't. this.boundKeyDownHandler = this.onKeyDown_.bind(this); this.input_.addEventListener('keydown', this.boundKeyDownHandler); } var invalid = this.element_.classList.contains(this.CssClasses_.IS_INVALID); this.updateClasses_(); this.element_.classList.add(this.CssClasses_.IS_UPGRADED); if (invalid) { this.element_.classList.add(this.CssClasses_.IS_INVALID); } if (this.input_.hasAttribute('autofocus')) { this.element_.focus(); this.checkFocus(); } } } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialTextfield, classAsString: 'MaterialTextfield', cssClass: 'mdl-js-textfield', widget: true }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Tooltip MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialTooltip = function MaterialTooltip(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialTooltip'] = MaterialTooltip; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialTooltip.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialTooltip.prototype.CssClasses_ = { IS_ACTIVE: 'is-active', BOTTOM: 'mdl-tooltip--bottom', LEFT: 'mdl-tooltip--left', RIGHT: 'mdl-tooltip--right', TOP: 'mdl-tooltip--top' }; /** * Handle mouseenter for tooltip. * * @param {Event} event The event that fired. * @private */ MaterialTooltip.prototype.handleMouseEnter_ = function (event) { var props = event.target.getBoundingClientRect(); var left = props.left + props.width / 2; var top = props.top + props.height / 2; var marginLeft = -1 * (this.element_.offsetWidth / 2); var marginTop = -1 * (this.element_.offsetHeight / 2); if (this.element_.classList.contains(this.CssClasses_.LEFT) || this.element_.classList.contains(this.CssClasses_.RIGHT)) { left = props.width / 2; if (top + marginTop < 0) { this.element_.style.top = '0'; this.element_.style.marginTop = '0'; } else { this.element_.style.top = top + 'px'; this.element_.style.marginTop = marginTop + 'px'; } } else { if (left + marginLeft < 0) { this.element_.style.left = '0'; this.element_.style.marginLeft = '0'; } else { this.element_.style.left = left + 'px'; this.element_.style.marginLeft = marginLeft + 'px'; } } if (this.element_.classList.contains(this.CssClasses_.TOP)) { this.element_.style.top = props.top - this.element_.offsetHeight - 10 + 'px'; } else if (this.element_.classList.contains(this.CssClasses_.RIGHT)) { this.element_.style.left = props.left + props.width + 10 + 'px'; } else if (this.element_.classList.contains(this.CssClasses_.LEFT)) { this.element_.style.left = props.left - this.element_.offsetWidth - 10 + 'px'; } else { this.element_.style.top = props.top + props.height + 10 + 'px'; } this.element_.classList.add(this.CssClasses_.IS_ACTIVE); }; /** * Hide tooltip on mouseleave or scroll * * @private */ MaterialTooltip.prototype.hideTooltip_ = function () { this.element_.classList.remove(this.CssClasses_.IS_ACTIVE); }; /** * Initialize element. */ MaterialTooltip.prototype.init = function () { if (this.element_) { var forElId = this.element_.getAttribute('for') || this.element_.getAttribute('data-mdl-for'); if (forElId) { this.forElement_ = document.getElementById(forElId); } if (this.forElement_) { // It's left here because it prevents accidental text selection on Android if (!this.forElement_.hasAttribute('tabindex')) { this.forElement_.setAttribute('tabindex', '0'); } this.boundMouseEnterHandler = this.handleMouseEnter_.bind(this); this.boundMouseLeaveAndScrollHandler = this.hideTooltip_.bind(this); this.forElement_.addEventListener('mouseenter', this.boundMouseEnterHandler, false); this.forElement_.addEventListener('touchend', this.boundMouseEnterHandler, false); this.forElement_.addEventListener('mouseleave', this.boundMouseLeaveAndScrollHandler, false); window.addEventListener('scroll', this.boundMouseLeaveAndScrollHandler, true); window.addEventListener('touchstart', this.boundMouseLeaveAndScrollHandler); } } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialTooltip, classAsString: 'MaterialTooltip', cssClass: 'mdl-tooltip' }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Layout MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialLayout = function MaterialLayout(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialLayout'] = MaterialLayout; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialLayout.prototype.Constant_ = { MAX_WIDTH: '(max-width: 1024px)', TAB_SCROLL_PIXELS: 100, RESIZE_TIMEOUT: 100, MENU_ICON: '', CHEVRON_LEFT: 'chevron_left', CHEVRON_RIGHT: 'chevron_right' }; /** * Keycodes, for code readability. * * @enum {number} * @private */ MaterialLayout.prototype.Keycodes_ = { ENTER: 13, ESCAPE: 27, SPACE: 32 }; /** * Modes. * * @enum {number} * @private */ MaterialLayout.prototype.Mode_ = { STANDARD: 0, SEAMED: 1, WATERFALL: 2, SCROLL: 3 }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialLayout.prototype.CssClasses_ = { CONTAINER: 'mdl-layout__container', HEADER: 'mdl-layout__header', DRAWER: 'mdl-layout__drawer', CONTENT: 'mdl-layout__content', DRAWER_BTN: 'mdl-layout__drawer-button', ICON: 'material-icons', JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect', RIPPLE_CONTAINER: 'mdl-layout__tab-ripple-container', RIPPLE: 'mdl-ripple', RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', HEADER_SEAMED: 'mdl-layout__header--seamed', HEADER_WATERFALL: 'mdl-layout__header--waterfall', HEADER_SCROLL: 'mdl-layout__header--scroll', FIXED_HEADER: 'mdl-layout--fixed-header', OBFUSCATOR: 'mdl-layout__obfuscator', TAB_BAR: 'mdl-layout__tab-bar', TAB_CONTAINER: 'mdl-layout__tab-bar-container', TAB: 'mdl-layout__tab', TAB_BAR_BUTTON: 'mdl-layout__tab-bar-button', TAB_BAR_LEFT_BUTTON: 'mdl-layout__tab-bar-left-button', TAB_BAR_RIGHT_BUTTON: 'mdl-layout__tab-bar-right-button', TAB_MANUAL_SWITCH: 'mdl-layout__tab-manual-switch', PANEL: 'mdl-layout__tab-panel', HAS_DRAWER: 'has-drawer', HAS_TABS: 'has-tabs', HAS_SCROLLING_HEADER: 'has-scrolling-header', CASTING_SHADOW: 'is-casting-shadow', IS_COMPACT: 'is-compact', IS_SMALL_SCREEN: 'is-small-screen', IS_DRAWER_OPEN: 'is-visible', IS_ACTIVE: 'is-active', IS_UPGRADED: 'is-upgraded', IS_ANIMATING: 'is-animating', ON_LARGE_SCREEN: 'mdl-layout--large-screen-only', ON_SMALL_SCREEN: 'mdl-layout--small-screen-only' }; /** * Handles scrolling on the content. * * @private */ MaterialLayout.prototype.contentScrollHandler_ = function () { if (this.header_.classList.contains(this.CssClasses_.IS_ANIMATING)) { return; } var headerVisible = !this.element_.classList.contains(this.CssClasses_.IS_SMALL_SCREEN) || this.element_.classList.contains(this.CssClasses_.FIXED_HEADER); if (this.content_.scrollTop > 0 && !this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) { this.header_.classList.add(this.CssClasses_.CASTING_SHADOW); this.header_.classList.add(this.CssClasses_.IS_COMPACT); if (headerVisible) { this.header_.classList.add(this.CssClasses_.IS_ANIMATING); } } else if (this.content_.scrollTop <= 0 && this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) { this.header_.classList.remove(this.CssClasses_.CASTING_SHADOW); this.header_.classList.remove(this.CssClasses_.IS_COMPACT); if (headerVisible) { this.header_.classList.add(this.CssClasses_.IS_ANIMATING); } } }; /** * Handles a keyboard event on the drawer. * * @param {Event} evt The event that fired. * @private */ MaterialLayout.prototype.keyboardEventHandler_ = function (evt) { // Only react when the drawer is open. if (evt.keyCode === this.Keycodes_.ESCAPE && this.drawer_.classList.contains(this.CssClasses_.IS_DRAWER_OPEN)) { this.toggleDrawer(); } }; /** * Handles changes in screen size. * * @private */ MaterialLayout.prototype.screenSizeHandler_ = function () { if (this.screenSizeMediaQuery_.matches) { this.element_.classList.add(this.CssClasses_.IS_SMALL_SCREEN); } else { this.element_.classList.remove(this.CssClasses_.IS_SMALL_SCREEN); // Collapse drawer (if any) when moving to a large screen size. if (this.drawer_) { this.drawer_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN); this.obfuscator_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN); } } }; /** * Handles events of drawer button. * * @param {Event} evt The event that fired. * @private */ MaterialLayout.prototype.drawerToggleHandler_ = function (evt) { if (evt && evt.type === 'keydown') { if (evt.keyCode === this.Keycodes_.SPACE || evt.keyCode === this.Keycodes_.ENTER) { // prevent scrolling in drawer nav evt.preventDefault(); } else { // prevent other keys return; } } this.toggleDrawer(); }; /** * Handles (un)setting the `is-animating` class * * @private */ MaterialLayout.prototype.headerTransitionEndHandler_ = function () { this.header_.classList.remove(this.CssClasses_.IS_ANIMATING); }; /** * Handles expanding the header on click * * @private */ MaterialLayout.prototype.headerClickHandler_ = function () { if (this.header_.classList.contains(this.CssClasses_.IS_COMPACT)) { this.header_.classList.remove(this.CssClasses_.IS_COMPACT); this.header_.classList.add(this.CssClasses_.IS_ANIMATING); } }; /** * Reset tab state, dropping active classes * * @private */ MaterialLayout.prototype.resetTabState_ = function (tabBar) { for (var k = 0; k < tabBar.length; k++) { tabBar[k].classList.remove(this.CssClasses_.IS_ACTIVE); } }; /** * Reset panel state, droping active classes * * @private */ MaterialLayout.prototype.resetPanelState_ = function (panels) { for (var j = 0; j < panels.length; j++) { panels[j].classList.remove(this.CssClasses_.IS_ACTIVE); } }; /** * Toggle drawer state * * @public */ MaterialLayout.prototype.toggleDrawer = function () { var drawerButton = this.element_.querySelector('.' + this.CssClasses_.DRAWER_BTN); this.drawer_.classList.toggle(this.CssClasses_.IS_DRAWER_OPEN); this.obfuscator_.classList.toggle(this.CssClasses_.IS_DRAWER_OPEN); // Set accessibility properties. if (this.drawer_.classList.contains(this.CssClasses_.IS_DRAWER_OPEN)) { this.drawer_.setAttribute('aria-hidden', 'false'); drawerButton.setAttribute('aria-expanded', 'true'); } else { this.drawer_.setAttribute('aria-hidden', 'true'); drawerButton.setAttribute('aria-expanded', 'false'); } }; MaterialLayout.prototype['toggleDrawer'] = MaterialLayout.prototype.toggleDrawer; /** * Initialize element. */ MaterialLayout.prototype.init = function () { if (this.element_) { var container = document.createElement('div'); container.classList.add(this.CssClasses_.CONTAINER); var focusedElement = this.element_.querySelector(':focus'); this.element_.parentElement.insertBefore(container, this.element_); this.element_.parentElement.removeChild(this.element_); container.appendChild(this.element_); if (focusedElement) { focusedElement.focus(); } var directChildren = this.element_.childNodes; var numChildren = directChildren.length; for (var c = 0; c < numChildren; c++) { var child = directChildren[c]; if (child.classList && child.classList.contains(this.CssClasses_.HEADER)) { this.header_ = child; } if (child.classList && child.classList.contains(this.CssClasses_.DRAWER)) { this.drawer_ = child; } if (child.classList && child.classList.contains(this.CssClasses_.CONTENT)) { this.content_ = child; } } window.addEventListener('pageshow', function (e) { if (e.persisted) { // when page is loaded from back/forward cache // trigger repaint to let layout scroll in safari this.element_.style.overflowY = 'hidden'; requestAnimationFrame(function () { this.element_.style.overflowY = ''; }.bind(this)); } }.bind(this), false); if (this.header_) { this.tabBar_ = this.header_.querySelector('.' + this.CssClasses_.TAB_BAR); } var mode = this.Mode_.STANDARD; if (this.header_) { if (this.header_.classList.contains(this.CssClasses_.HEADER_SEAMED)) { mode = this.Mode_.SEAMED; } else if (this.header_.classList.contains(this.CssClasses_.HEADER_WATERFALL)) { mode = this.Mode_.WATERFALL; this.header_.addEventListener('transitionend', this.headerTransitionEndHandler_.bind(this)); this.header_.addEventListener('click', this.headerClickHandler_.bind(this)); } else if (this.header_.classList.contains(this.CssClasses_.HEADER_SCROLL)) { mode = this.Mode_.SCROLL; container.classList.add(this.CssClasses_.HAS_SCROLLING_HEADER); } if (mode === this.Mode_.STANDARD) { this.header_.classList.add(this.CssClasses_.CASTING_SHADOW); if (this.tabBar_) { this.tabBar_.classList.add(this.CssClasses_.CASTING_SHADOW); } } else if (mode === this.Mode_.SEAMED || mode === this.Mode_.SCROLL) { this.header_.classList.remove(this.CssClasses_.CASTING_SHADOW); if (this.tabBar_) { this.tabBar_.classList.remove(this.CssClasses_.CASTING_SHADOW); } } else if (mode === this.Mode_.WATERFALL) { // Add and remove shadows depending on scroll position. // Also add/remove auxiliary class for styling of the compact version of // the header. this.content_.addEventListener('scroll', this.contentScrollHandler_.bind(this)); this.contentScrollHandler_(); } } // Add drawer toggling button to our layout, if we have an openable drawer. if (this.drawer_) { var drawerButton = this.element_.querySelector('.' + this.CssClasses_.DRAWER_BTN); if (!drawerButton) { drawerButton = document.createElement('div'); drawerButton.setAttribute('aria-expanded', 'false'); drawerButton.setAttribute('role', 'button'); drawerButton.setAttribute('tabindex', '0'); drawerButton.classList.add(this.CssClasses_.DRAWER_BTN); var drawerButtonIcon = document.createElement('i'); drawerButtonIcon.classList.add(this.CssClasses_.ICON); drawerButtonIcon.innerHTML = this.Constant_.MENU_ICON; drawerButton.appendChild(drawerButtonIcon); } if (this.drawer_.classList.contains(this.CssClasses_.ON_LARGE_SCREEN)) { //If drawer has ON_LARGE_SCREEN class then add it to the drawer toggle button as well. drawerButton.classList.add(this.CssClasses_.ON_LARGE_SCREEN); } else if (this.drawer_.classList.contains(this.CssClasses_.ON_SMALL_SCREEN)) { //If drawer has ON_SMALL_SCREEN class then add it to the drawer toggle button as well. drawerButton.classList.add(this.CssClasses_.ON_SMALL_SCREEN); } drawerButton.addEventListener('click', this.drawerToggleHandler_.bind(this)); drawerButton.addEventListener('keydown', this.drawerToggleHandler_.bind(this)); // Add a class if the layout has a drawer, for altering the left padding. // Adds the HAS_DRAWER to the elements since this.header_ may or may // not be present. this.element_.classList.add(this.CssClasses_.HAS_DRAWER); // If we have a fixed header, add the button to the header rather than // the layout. if (this.element_.classList.contains(this.CssClasses_.FIXED_HEADER)) { this.header_.insertBefore(drawerButton, this.header_.firstChild); } else { this.element_.insertBefore(drawerButton, this.content_); } var obfuscator = document.createElement('div'); obfuscator.classList.add(this.CssClasses_.OBFUSCATOR); this.element_.appendChild(obfuscator); obfuscator.addEventListener('click', this.drawerToggleHandler_.bind(this)); this.obfuscator_ = obfuscator; this.drawer_.addEventListener('keydown', this.keyboardEventHandler_.bind(this)); this.drawer_.setAttribute('aria-hidden', 'true'); } // Keep an eye on screen size, and add/remove auxiliary class for styling // of small screens. this.screenSizeMediaQuery_ = window.matchMedia(this.Constant_.MAX_WIDTH); this.screenSizeMediaQuery_.addListener(this.screenSizeHandler_.bind(this)); this.screenSizeHandler_(); // Initialize tabs, if any. if (this.header_ && this.tabBar_) { this.element_.classList.add(this.CssClasses_.HAS_TABS); var tabContainer = document.createElement('div'); tabContainer.classList.add(this.CssClasses_.TAB_CONTAINER); this.header_.insertBefore(tabContainer, this.tabBar_); this.header_.removeChild(this.tabBar_); var leftButton = document.createElement('div'); leftButton.classList.add(this.CssClasses_.TAB_BAR_BUTTON); leftButton.classList.add(this.CssClasses_.TAB_BAR_LEFT_BUTTON); var leftButtonIcon = document.createElement('i'); leftButtonIcon.classList.add(this.CssClasses_.ICON); leftButtonIcon.textContent = this.Constant_.CHEVRON_LEFT; leftButton.appendChild(leftButtonIcon); leftButton.addEventListener('click', function () { this.tabBar_.scrollLeft -= this.Constant_.TAB_SCROLL_PIXELS; }.bind(this)); var rightButton = document.createElement('div'); rightButton.classList.add(this.CssClasses_.TAB_BAR_BUTTON); rightButton.classList.add(this.CssClasses_.TAB_BAR_RIGHT_BUTTON); var rightButtonIcon = document.createElement('i'); rightButtonIcon.classList.add(this.CssClasses_.ICON); rightButtonIcon.textContent = this.Constant_.CHEVRON_RIGHT; rightButton.appendChild(rightButtonIcon); rightButton.addEventListener('click', function () { this.tabBar_.scrollLeft += this.Constant_.TAB_SCROLL_PIXELS; }.bind(this)); tabContainer.appendChild(leftButton); tabContainer.appendChild(this.tabBar_); tabContainer.appendChild(rightButton); // Add and remove tab buttons depending on scroll position and total // window size. var tabUpdateHandler = function () { if (this.tabBar_.scrollLeft > 0) { leftButton.classList.add(this.CssClasses_.IS_ACTIVE); } else { leftButton.classList.remove(this.CssClasses_.IS_ACTIVE); } if (this.tabBar_.scrollLeft < this.tabBar_.scrollWidth - this.tabBar_.offsetWidth) { rightButton.classList.add(this.CssClasses_.IS_ACTIVE); } else { rightButton.classList.remove(this.CssClasses_.IS_ACTIVE); } }.bind(this); this.tabBar_.addEventListener('scroll', tabUpdateHandler); tabUpdateHandler(); // Update tabs when the window resizes. var windowResizeHandler = function () { // Use timeouts to make sure it doesn't happen too often. if (this.resizeTimeoutId_) { clearTimeout(this.resizeTimeoutId_); } this.resizeTimeoutId_ = setTimeout(function () { tabUpdateHandler(); this.resizeTimeoutId_ = null; }.bind(this), this.Constant_.RESIZE_TIMEOUT); }.bind(this); window.addEventListener('resize', windowResizeHandler); if (this.tabBar_.classList.contains(this.CssClasses_.JS_RIPPLE_EFFECT)) { this.tabBar_.classList.add(this.CssClasses_.RIPPLE_IGNORE_EVENTS); } // Select element tabs, document panels var tabs = this.tabBar_.querySelectorAll('.' + this.CssClasses_.TAB); var panels = this.content_.querySelectorAll('.' + this.CssClasses_.PANEL); // Create new tabs for each tab element for (var i = 0; i < tabs.length; i++) { new MaterialLayoutTab(tabs[i], tabs, panels, this); } } this.element_.classList.add(this.CssClasses_.IS_UPGRADED); } }; /** * Constructor for an individual tab. * * @constructor * @param {HTMLElement} tab The HTML element for the tab. * @param {!Array} tabs Array with HTML elements for all tabs. * @param {!Array} panels Array with HTML elements for all panels. * @param {MaterialLayout} layout The MaterialLayout object that owns the tab. */ function MaterialLayoutTab(tab, tabs, panels, layout) { /** * Auxiliary method to programmatically select a tab in the UI. */ function selectTab() { var href = tab.href.split('#')[1]; var panel = layout.content_.querySelector('#' + href); layout.resetTabState_(tabs); layout.resetPanelState_(panels); tab.classList.add(layout.CssClasses_.IS_ACTIVE); panel.classList.add(layout.CssClasses_.IS_ACTIVE); } if (layout.tabBar_.classList.contains(layout.CssClasses_.JS_RIPPLE_EFFECT)) { var rippleContainer = document.createElement('span'); rippleContainer.classList.add(layout.CssClasses_.RIPPLE_CONTAINER); rippleContainer.classList.add(layout.CssClasses_.JS_RIPPLE_EFFECT); var ripple = document.createElement('span'); ripple.classList.add(layout.CssClasses_.RIPPLE); rippleContainer.appendChild(ripple); tab.appendChild(rippleContainer); } if (!layout.tabBar_.classList.contains(layout.CssClasses_.TAB_MANUAL_SWITCH)) { tab.addEventListener('click', function (e) { if (( tab.getAttribute('href') !== null ) && (tab.getAttribute('href').charAt(0) === '#')) { e.preventDefault(); selectTab(); } }); } tab.show = selectTab; } window['MaterialLayoutTab'] = MaterialLayoutTab; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialLayout, classAsString: 'MaterialLayout', cssClass: 'mdl-js-layout' }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Data Table Card MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {Element} element The element that will be upgraded. */ var MaterialDataTable = function MaterialDataTable(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialDataTable'] = MaterialDataTable; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialDataTable.prototype.Constant_ = {}; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialDataTable.prototype.CssClasses_ = { DATA_TABLE: 'mdl-data-table', SELECTABLE: 'mdl-data-table--selectable', SELECT_ELEMENT: 'mdl-data-table__select', IS_SELECTED: 'is-selected', IS_UPGRADED: 'is-upgraded' }; /** * Generates and returns a function that toggles the selection state of a * single row (or multiple rows). * * @param {Element} checkbox Checkbox that toggles the selection state. * @param {Element} row Row to toggle when checkbox changes. * @param {(Array|NodeList)=} opt_rows Rows to toggle when checkbox changes. * @private */ MaterialDataTable.prototype.selectRow_ = function (checkbox, row, opt_rows) { if (row) { return function () { if (checkbox.checked) { row.classList.add(this.CssClasses_.IS_SELECTED); } else { row.classList.remove(this.CssClasses_.IS_SELECTED); } }.bind(this); } if (opt_rows) { return function () { var i; var el; if (checkbox.checked) { for (i = 0; i < opt_rows.length; i++) { el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox'); el['MaterialCheckbox'].check(); opt_rows[i].classList.add(this.CssClasses_.IS_SELECTED); } } else { for (i = 0; i < opt_rows.length; i++) { el = opt_rows[i].querySelector('td').querySelector('.mdl-checkbox'); el['MaterialCheckbox'].uncheck(); opt_rows[i].classList.remove(this.CssClasses_.IS_SELECTED); } } }.bind(this); } }; /** * Creates a checkbox for a single or or multiple rows and hooks up the * event handling. * * @param {Element} row Row to toggle when checkbox changes. * @param {(Array|NodeList)=} opt_rows Rows to toggle when checkbox changes. * @private */ MaterialDataTable.prototype.createCheckbox_ = function (row, opt_rows) { var label = document.createElement('label'); var labelClasses = [ 'mdl-checkbox', 'mdl-js-checkbox', 'mdl-js-ripple-effect', this.CssClasses_.SELECT_ELEMENT ]; label.className = labelClasses.join(' '); var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.classList.add('mdl-checkbox__input'); if (row) { checkbox.checked = row.classList.contains(this.CssClasses_.IS_SELECTED); checkbox.addEventListener('change', this.selectRow_(checkbox, row)); } else if (opt_rows) { checkbox.addEventListener('change', this.selectRow_(checkbox, null, opt_rows)); } label.appendChild(checkbox); componentHandler.upgradeElement(label, 'MaterialCheckbox'); return label; }; /** * Initialize element. */ MaterialDataTable.prototype.init = function () { if (this.element_) { var firstHeader = this.element_.querySelector('th'); var bodyRows = Array.prototype.slice.call(this.element_.querySelectorAll('tbody tr')); var footRows = Array.prototype.slice.call(this.element_.querySelectorAll('tfoot tr')); var rows = bodyRows.concat(footRows); if (this.element_.classList.contains(this.CssClasses_.SELECTABLE)) { var th = document.createElement('th'); var headerCheckbox = this.createCheckbox_(null, rows); th.appendChild(headerCheckbox); firstHeader.parentElement.insertBefore(th, firstHeader); for (var i = 0; i < rows.length; i++) { var firstCell = rows[i].querySelector('td'); if (firstCell) { var td = document.createElement('td'); if (rows[i].parentNode.nodeName.toUpperCase() === 'TBODY') { var rowCheckbox = this.createCheckbox_(rows[i]); td.appendChild(rowCheckbox); } rows[i].insertBefore(td, firstCell); } } this.element_.classList.add(this.CssClasses_.IS_UPGRADED); } } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialDataTable, classAsString: 'MaterialDataTable', cssClass: 'mdl-js-data-table' }); /** * @license * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Class constructor for Ripple MDL component. * Implements MDL component design pattern defined at: * https://github.com/jasonmayes/mdl-component-design-pattern * * @constructor * @param {HTMLElement} element The element that will be upgraded. */ var MaterialRipple = function MaterialRipple(element) { this.element_ = element; // Initialize instance. this.init(); }; window['MaterialRipple'] = MaterialRipple; /** * Store constants in one place so they can be updated easily. * * @enum {string | number} * @private */ MaterialRipple.prototype.Constant_ = { INITIAL_SCALE: 'scale(0.0001, 0.0001)', INITIAL_SIZE: '1px', INITIAL_OPACITY: '0.4', FINAL_OPACITY: '0', FINAL_SCALE: '' }; /** * Store strings for class names defined by this component that are used in * JavaScript. This allows us to simply change it in one place should we * decide to modify at a later date. * * @enum {string} * @private */ MaterialRipple.prototype.CssClasses_ = { RIPPLE_CENTER: 'mdl-ripple--center', RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events', RIPPLE: 'mdl-ripple', IS_ANIMATING: 'is-animating', IS_VISIBLE: 'is-visible' }; /** * Handle mouse / finger down on element. * * @param {Event} event The event that fired. * @private */ MaterialRipple.prototype.downHandler_ = function (event) { if (!this.rippleElement_.style.width && !this.rippleElement_.style.height) { var rect = this.element_.getBoundingClientRect(); this.boundHeight = rect.height; this.boundWidth = rect.width; this.rippleSize_ = Math.sqrt(rect.width * rect.width + rect.height * rect.height) * 2 + 2; this.rippleElement_.style.width = this.rippleSize_ + 'px'; this.rippleElement_.style.height = this.rippleSize_ + 'px'; } this.rippleElement_.classList.add(this.CssClasses_.IS_VISIBLE); if (event.type === 'mousedown' && this.ignoringMouseDown_) { this.ignoringMouseDown_ = false; } else { if (event.type === 'touchstart') { this.ignoringMouseDown_ = true; } var frameCount = this.getFrameCount(); if (frameCount > 0) { return; } this.setFrameCount(1); var bound = event.currentTarget.getBoundingClientRect(); var x; var y; // Check if we are handling a keyboard click. if (event.clientX === 0 && event.clientY === 0) { x = Math.round(bound.width / 2); y = Math.round(bound.height / 2); } else { var clientX = event.clientX !== undefined ? event.clientX : event.touches[0].clientX; var clientY = event.clientY !== undefined ? event.clientY : event.touches[0].clientY; x = Math.round(clientX - bound.left); y = Math.round(clientY - bound.top); } this.setRippleXY(x, y); this.setRippleStyles(true); window.requestAnimationFrame(this.animFrameHandler.bind(this)); } }; /** * Handle mouse / finger up on element. * * @param {Event} event The event that fired. * @private */ MaterialRipple.prototype.upHandler_ = function (event) { // Don't fire for the artificial "mouseup" generated by a double-click. if (event && event.detail !== 2) { // Allow a repaint to occur before removing this class, so the animation // shows for tap events, which seem to trigger a mouseup too soon after // mousedown. window.setTimeout(function () { this.rippleElement_.classList.remove(this.CssClasses_.IS_VISIBLE); }.bind(this), 0); } }; /** * Initialize element. */ MaterialRipple.prototype.init = function () { if (this.element_) { var recentering = this.element_.classList.contains(this.CssClasses_.RIPPLE_CENTER); if (!this.element_.classList.contains(this.CssClasses_.RIPPLE_EFFECT_IGNORE_EVENTS)) { this.rippleElement_ = this.element_.querySelector('.' + this.CssClasses_.RIPPLE); this.frameCount_ = 0; this.rippleSize_ = 0; this.x_ = 0; this.y_ = 0; // Touch start produces a compat mouse down event, which would cause a // second ripples. To avoid that, we use this property to ignore the first // mouse down after a touch start. this.ignoringMouseDown_ = false; this.boundDownHandler = this.downHandler_.bind(this); this.element_.addEventListener('mousedown', this.boundDownHandler); this.element_.addEventListener('touchstart', this.boundDownHandler); this.boundUpHandler = this.upHandler_.bind(this); this.element_.addEventListener('mouseup', this.boundUpHandler); this.element_.addEventListener('mouseleave', this.boundUpHandler); this.element_.addEventListener('touchend', this.boundUpHandler); this.element_.addEventListener('blur', this.boundUpHandler); /** * Getter for frameCount_. * @return {number} the frame count. */ this.getFrameCount = function () { return this.frameCount_; }; /** * Setter for frameCount_. * @param {number} fC the frame count. */ this.setFrameCount = function (fC) { this.frameCount_ = fC; }; /** * Getter for rippleElement_. * @return {Element} the ripple element. */ this.getRippleElement = function () { return this.rippleElement_; }; /** * Sets the ripple X and Y coordinates. * @param {number} newX the new X coordinate * @param {number} newY the new Y coordinate */ this.setRippleXY = function (newX, newY) { this.x_ = newX; this.y_ = newY; }; /** * Sets the ripple styles. * @param {boolean} start whether or not this is the start frame. */ this.setRippleStyles = function (start) { if (this.rippleElement_ !== null) { var transformString; var scale; var size; var offset = 'translate(' + this.x_ + 'px, ' + this.y_ + 'px)'; if (start) { scale = this.Constant_.INITIAL_SCALE; size = this.Constant_.INITIAL_SIZE; } else { scale = this.Constant_.FINAL_SCALE; size = this.rippleSize_ + 'px'; if (recentering) { offset = 'translate(' + this.boundWidth / 2 + 'px, ' + this.boundHeight / 2 + 'px)'; } } transformString = 'translate(-50%, -50%) ' + offset + scale; this.rippleElement_.style.webkitTransform = transformString; this.rippleElement_.style.msTransform = transformString; this.rippleElement_.style.transform = transformString; if (start) { this.rippleElement_.classList.remove(this.CssClasses_.IS_ANIMATING); } else { this.rippleElement_.classList.add(this.CssClasses_.IS_ANIMATING); } } }; /** * Handles an animation frame. */ this.animFrameHandler = function () { if (this.frameCount_-- > 0) { window.requestAnimationFrame(this.animFrameHandler.bind(this)); } else { this.setRippleStyles(false); } }; } } }; // The component registers itself. It can assume componentHandler is available // in the global scope. componentHandler.register({ constructor: MaterialRipple, classAsString: 'MaterialRipple', cssClass: 'mdl-js-ripple-effect', widget: false }); }()); // END MDL $(document).ready( function() { // snackbar wrapper for dual-language support function ShowMessage( english , french , type ) { $(".mdl-snackbar").removeClass("error ok"); switch ( $("html").attr("lang")) { case "fr": var msg = french; break; case "en": default: var msg = english; break; } switch ( type ) { case ERROR: $(".mdl-snackbar").addClass("error"); break; case INFO: $(".mdl-snackbar").addClass("info"); break; case OK: default: $(".mdl-snackbar").addClass("ok"); break; } var snackbarContainer = document.querySelector('#toast'); snackbarContainer.MaterialSnackbar.showSnackbar({ message: msg , timeout: 5000 }); } function epic_UpdateLanguage ( newlanguage , updateSession = false ) { switch ( newlanguage ) { case "fr": $("html").attr("lang" , "fr"); $( "*[lang='en']" ).addClass("hide"); $( "*[lang='fr']" ).removeClass("hide"); break; case "en": default: $("html").attr("lang" , "en"); $( "*[lang='fr']" ).addClass("hide"); $( "*[lang='en']" ).removeClass("hide"); break; } if ( updateSession ) { //now update the session var url = "https://gala.epic.foundation/language"; window.ajaxObj = $.ajax({ url: url, dataType: "json", method: "POST", data: { epic_cookie_lang: newlanguage }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Failed to save your language preferences.", "Votre préférence de langue n'a pu être enregistrée.", ERROR ); } }, success: function(data, status, request) { ShowMessage("Your language preference has been saved.", "Votre préférence de langue a été enregistrée.", OK ); } }); } } $(".mdl-layout__tab").click( function ( event ) { $(".page-content").animate({ scrollTop: 0 }, "fast"); }); $(".program__link").click( function ( event ) { $("section").removeClass("is-active"); $("#program").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.program__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); ScrollToTop(); }); $(".activity__link").click( function ( event ) { $("section").removeClass("is-active"); $("#activity").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.activity__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); ClearActivityNotifications(); ScrollToTop(); }); $(".auction-winner__link").click( function ( event ) { $("section").removeClass("is-active"); $("#auction-winner").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.auction-winner__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); AdminFetchLiveAuctionItems (); ScrollToTop(); }); $(".admin__link").click( function ( event ) { $("section").removeClass("is-active"); $("#admin").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.admin__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); UpdateProbability(); UpdateCounters(); FetchAdminAuctionItems (); ScrollToTop(); }); $(".portfolio__link").click( function ( event ) { $("section").removeClass("is-active"); $("#portfolio").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.portfolio__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); if ($("#portfolio-organizations").html() == "" ) { getOrganizations(); } else { $(".org-intros").addClass("hide"); $(".read-more-button").removeClass("hide"); } ScrollToTop(); }); $(".auction__link").click( function ( event ) { $("section").removeClass("is-active"); $("#auction").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.auction__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); ClearNoLongerHighestBidderNotifications(); ScrollToTop(); }); $(".raffle__link").click( function ( event ) { $("section").removeClass("is-active"); $("#raffle").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.raffle__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); ScrollToTop(); }); $(".donate__link").click( function ( event ) { $("section").removeClass("is-active"); $("#donate").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.donate__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); ScrollToTop(); }); $(".fund-a-need__link").click( function ( event ) { $("section").removeClass("is-active"); $("#fund-a-need").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.fund-a-need__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); ScrollToTop(); }); $(".checkin__link").click( function ( event ) { $("section").removeClass("is-active"); $("#checkin").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.checkin__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); $("#search_guest_input").val(""); $("#search_guest_input").focus(); $("#search_guest_input").select(); ScrollToTop(); }); $(".audit__link").click( function ( event ) { $("section").removeClass("is-active"); $("#audit").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.audit__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); $("#audit_search_guest_input").val(""); $("#audit_search_guest_input").focus(); $("#audit_search_guest_input").select(); $("#audit_guest_name").html(""); $("#audit_guest_id").html(""); $("#audit_search_guest_results").html(""); $("#audit_total_pledged").html(""); ScrollToTop(); }); $(".reconcile__link").click( function ( event ) { $("section").removeClass("is-active"); $("#reconcile").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.reconcile__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); $("#reconciliation_search_guest_input").val(""); $("#reconciliation_search_guest_input").focus(); $("#reconciliation_search_guest_input").select(); $(".guest-pledge-total").html(""); $("#reconciliation_guest_name,#reconciliation-amount,#reconciliation_guest_id,#reconciliation_total_pledged").html(""); ScrollToTop(); }); $(".checkout__link").click( function ( event ) { $("section").removeClass("is-active"); $("#checkout").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.checkout__link").addClass("is-active"); $(".mdl-layout__drawer.is-visible").removeClass("is-visible"); $("#itemized-tab").addClass("hide"); $("#show-itemization").removeClass("hide"); $("hide-itemization").addClass("hide"); $(".guest-pledge-total").html(""); PopulateTotal(); ScrollToTop(); }); function ScrollToTop () { $('main').animate({ scrollTop: 0 }, 500); } $("#online button").click( function() { var type = $(this).closest("button").data("receipt"); if ( typeof type != "undefined" ) { var url = 'https://api.epic.foundation/gala/guest/audit'; $.ajax({ url: url, dataType: "json", method: "POST", data: { guestId: window.gala_guest_id, EPIC_AGENT_ID_PARAMETER: GetStewartId(), EPIC_AUDIT_LEVEL_PARAMETER: "Info", qual1: "Online checkout initiated", qual2: type, qual3: "", access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("This event could not be audited.", "Initiation du paiement électrique non-enregistrée.", ERROR ); } }, success: function(data, status, request) { ShowMessage("Please complete your online payment in the new window.", "Veuillez compléter votre paiement dans la nouvelle fenêtre.", OK ); } }); } }); $("button.instructions").click( function () { var type = $(this).closest(".instructions").data("receipt"); if ( typeof type != "undefined" ) { // the sending of email lasts several seconds: show a progressbar $("#gala_obfuscator").addClass("is-visible"); $("#email-centralizer").removeClass("hide"); var url = 'https://api.epic.foundation/gala/guest/tab/email'; $.ajax({ url: url, dataType: "json", method: "POST", data: { guestId: window.gala_guest_id, receipt: type, epic_lang: $("html").attr("lang"), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("The email could not be sent because of a connectivity issue. Please see an Epic steward at checkout.", "L'email n'a pas pu être envoyé à cause d'un problème de connexion. Merci de consulter un membre de l'équipe Epic avant de quitter l'Epic Night.", ERROR ); $("#gala_obfuscator").removeClass("is-visible"); $("#email-centralizer").addClass("hide"); } }, success: function(data, status, request) { if ( data && Object.keys(data).length > 0 && typeof data != "undefined" && typeof data.status != "undefined" && data.status == "OK" ) { ShowMessage("An email has been sent to you. Thank you for attending the Epic Night tonight!", "Un email vous a été envoyé. Merci d'avoir participé à l'Epic Night !", OK ); $("#gala_obfuscator").removeClass("is-visible"); $("#email-centralizer").addClass("hide"); } else { ShowMessage("The email could not be sent. Please see an Epic steward at checkout.", "L'email n'a pas pu être envoyé. Merci de consulter un membre de l'équipe Epic avant de quitter l'Epic Night.", ERROR ); $("#gala_obfuscator").removeClass("is-visible"); $("#email-centralizer").addClass("hide"); } } }); } }); $("#email-centralizer,#facts-centralizer").click( function ( event ) { $(this).addClass("hide"); $("#gala_obfuscator").removeClass("is-visible"); }); $("#raffle-purchase-wrapper input[type='range']").change( function () { $(".number-of-tickets").html( $("#raffle-purchase-wrapper input[type='range']").val()); if ( $("#raffle-purchase-wrapper input[type='range']").val() > 1 ) { $(".ticket-s").html( "s" ); } else { $(".ticket-s").html( "" ); } }); $("#activity-purchase-wrapper input[type='range']").change( function () { $(".number-of-activity-tickets").html( $("#activity-purchase-wrapper input[type='range']").val()); if ( $("#activity-purchase-wrapper input[type='range']").val() > 1 ) { $(".activity-ticket-s").html( "s" ); } else { $(".activity-ticket-s").html( "" ); } }); //initialization $(".number-of-tickets").html( $("#raffle-purchase-wrapper input[type='range']").val()); if ( $("#raffle-purchase-wrapper input[type='range']").val() > 1 ) { $(".ticket-s").html( "s" ); } else { $(".ticket-s").html( "" ); } $(".number-of-activity-tickets").html( $("#activity-purchase-wrapper input[type='range']").val()); if ( $("#activity-purchase-wrapper input[type='range']").val() > 1 ) { $(".activity-ticket-s").html( "s" ); } else { $(".activity-ticket-s").html( "" ); } $(".mdl-navigation__link, .mdl-layout__drawer, .mdl-layout__obfuscator.is-visible, #gala_obfuscator.is-visible").click( function() {$(".mdl-layout__drawer.is-visible, .mdl-layout__obfuscator.is-visible, #gala_obfuscator.is-visible").removeClass("is-visible"); }); // handles language change requests $(".language-french").click( function () { epic_UpdateLanguage ( "fr" , true ); }); $(".language-english").click( function () { epic_UpdateLanguage ( "en" , true ); }); // If the language is already defined, show the splash and after 3s, // show the login if ( $("html").data("origin") == "cookie") { epic_UpdateLanguage( $("html").attr("lang") , false ); setTimeout( function () { $("#splash,#language-centralizer").addClass("hide"); $("#login").removeClass("hide"); $("section").removeClass("is-active"); $("#login").addClass("is-active"); } , 3000 ); } else { $("#splash,#language-centralizer").removeClass("hide"); } $("#login-input span").click( function ( event) { if ($(this).data("number") !== undefined ) { $('#login_identifier').html($('#login_identifier').html() + $(this).data("number")); } $(this).addClass("active"); var target = $(this); setTimeout( RemoveActiveClass , 300 , target ); event.stopPropagation(); }); $("#donation-input span").click( function ( event) { if ($(this).data("number") !== undefined ) { $('#donation-amount').html( PrettyPrintCurrency( window.gala_currency , $('#donation-amount').html().replace(/\D/g,'') + $(this).data("number"))); } $(this).addClass("active"); var target = $(this); setTimeout( RemoveActiveClass , 300 , target ); event.stopPropagation(); }); $("#fund-a-need-input span").click( function ( event) { if ($(this).data("number") !== undefined ) { $('#fund-a-need-guest').html( $("#fund-a-need-guest").html() + $(this).data("number")); } $(this).addClass("active"); var target = $(this); setTimeout( RemoveActiveClass , 300 , target ); event.stopPropagation(); }); $("#reconciliation-input span").click( function ( event) { if ($(this).data("number") !== undefined ) { $('#reconciliation-amount').html( PrettyPrintCurrency( window.gala_currency , $("#reconciliation-amount").html().replace(/\D/g,'') + $(this).data("number"))); } $(this).addClass("active"); var target = $(this); setTimeout( RemoveActiveClass , 300 , target ); event.stopPropagation(); }); function RemoveActiveClass ( jQueryObj ) { jQueryObj.removeClass("active"); } $("#backspace-login").click( function (event) { $('#login_identifier').html($('#login_identifier').html().slice(0,-1).replace(/\D/g,'')); }); $("#backspace-reconciliation").click( function (event) { $('#reconciliation-amount').html( PrettyPrintCurrency( window.gala_currency , $('#reconciliation-amount').html().slice(0,-1).replace(/\D/g,''))); }); $("#backspace-donation").click( function (event) { $("#donation-amount").html( PrettyPrintCurrency( window.gala_currency , $("#donation-amount").html().slice(0,-1).replace(/\D/g,''))); }); $("#backspace-fund-a-need").click( function (event) { $("#fund-a-need-guest").html( $("#fund-a-need-guest").html().slice(0,-1)); }); // login process $("#login-submit").click(function() { var url = "https://api.epic.foundation/oauth2/get-token"; $.ajax({ url: url, dataType: "json", method: "POST", guest_id: $("#login_identifier").html(), data: { grant_type: "client_credentials", client_id: $("#login_identifier").html(), client_secret: md5($("#login_identifier").html()) }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { if ( (typeof object.responseJSON != "undefined") && ( typeof object.responseJSON.error != "undefined" ) && ( object.responseJSON.error == "invalid_client") ) { ShowMessage( "Please checkin with an Epic steward to activate your profile." , "Votre profil n'est pas encore actif. Veuillez consulter un membre de l'équipe d'Epic pour l'activer." , ERROR ); } else { ShowMessage("Your identifier could not be recognized.", "Votre identifiant n'a pas été reconnu.", ERROR ); } } ResetLogin(); }, success: function(data, status, request ) { if ( data && Object.keys(data).length > 0 && typeof data != "undefined" && typeof data.scope != "undefined" && data.scope.length > 0 ) { switch( data.scope.toString().split(" ").slice(-1)[0] ) { case "gala-guest": if ( typeof data.access_token != "undefined" ) { window.access_token = data.access_token; window.stewart_access_token = ""; window.admin_access_token = ""; window.gala_guest_id = this.guest_id; window.gala_stewart_id = ""; window.gala_admin_id = ""; LocalizeGala(); CustomizeInterface( "gala-guest" ); ShowMessage("Welcome!", "Bienvenue!", OK ); $("#login").addClass("hide"); $("#login").removeClass("is-active"); $(".mdl-layout__header, .program__link, .checkout__link, .auction__link, .raffle__link, .portfolio__link, .donate__link").removeClass("hide"); $("#program, #auction, #raffle, #checkout, #donate, #portfolio").removeClass("hide"); $(".mdl-layout__tab").removeClass("is-active"); $("#program").addClass("is-active"); $(".mdl-layout__tab.program__link").addClass("is-active"); getOrganizations(); } else { ShowMessage("Your login token was not provided: please see a member of the Epic Team.", "Erreur de clé de sécurité. Veuillez consulter un membre de l'Equipe Epic", ERROR ); } break; case "gala-stewart": if ( typeof data.access_token != "undefined") { window.access_token = ""; window.stewart_access_token = data.access_token; window.admin_access_token = ""; window.gala_guest_id = ""; window.gala_stewart_id = this.guest_id; window.gala_admin_id = ""; LocalizeGala(); CustomizeInterface( "gala-stewart" ); ShowMessage("Welcome, Stewart!", "Bienvenue Epic Stewart!", OK ); $("#login").addClass("hide"); $("#login").removeClass("is-active"); $(".mdl-layout__header, .checkin__link, .program__link, .portfolio__link, .audit__link").removeClass("hide"); $("#checkin,#program, #portfolio, #audit").removeClass("hide"); $("#program").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.program__link").addClass("is-active"); getOrganizations(); } else { ShowMessage("Your login token was not provided: please see a member of the Epic Team.", "Erreur de clé de sécurité. Veuillez consulter un membre de l'Equipe Epic", ERROR ); } break; case "gala-admin": if ( typeof data.access_token != "undefined") { window.access_token = ""; window.stewart_access_token = ""; window.admin_access_token = data.access_token; window.gala_guest_id = ""; window.gala_stewart_id = ""; window.gala_admin_id = this.guest_id; LocalizeGala(); CustomizeInterface( "gala-admin" ); ShowMessage("Welcome Admin!", "Bienvenue, Admin!", OK ); $("#login").addClass("hide"); $("#login").removeClass("is-active"); $(".mdl-layout__header, .checkin__link, .program__link, .auction-winner__link, .reconcile__link, .admin__link, .portfolio__link, .audit__link, .fund-a-need__link").removeClass("hide"); $("#checkin,#program, #portfolio, #admin, #audit, #reconcile, #auction-winner, #fund-a-need").removeClass("hide"); $("#program").addClass("is-active"); $(".mdl-layout__tab").removeClass("is-active"); $(".mdl-layout__tab.program__link").addClass("is-active"); getOrganizations(); } else { ShowMessage("Your login token was not provided: please see a member of the Epic Team.", "Erreur de clé de sécurité. Veuillez consulter un membre de l'Equipe Epic", ERROR ); } break; default: ShowMessage("Your profile is not activated yet. Please go to checkin. ", "Votre profil n'est pas encore activé. Veuillez vous rendre à l'accueil.", OK ); ResetLogin(); break; } } else { ShowMessage("Activation error: please see a member of the Epic Team. ", "Erreur d'activation. Veuillez consulter un membre de l'Equipe Epic.", ERROR ); ResetLogin(); } } }); event.stopPropagation(); }); $("#hide-itemization").click( function ( event ) { $("#show-itemization").removeClass("hide"); $("#hide-itemization").addClass("hide"); $("#itemized-tab-tbody").html(""); }); $("#show-itemization").click( function ( event ) { var url = "https://api.epic.foundation/gala/guest/tab"; $("#show-itemization").addClass("hide"); $("#hide-itemization").removeClass("hide"); $.ajax({ url: url, dataType: "json", method: "GET", data: { guestId : window.gala_guest_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Your tab could not be retrieved. Please see a steward.", "Les détails de votre compte n'ont pu être trouvés. Veuillez demander à un membre de l'équipe d'Epic.", ERROR ); } }, success: function(data, status, request , guest_id) { if ( data && (Object.keys(data).length > 0 ) && (typeof data != "undefined" ) && (typeof data.pledges != "undefined" ) && (Object.keys(data.pledges).length > 0 )) { $("#itemized-tab-tbody").html(""); $.each( data.pledges , function ( index , element) { $("#itemized-tab-tbody").append("\ \ \ " + element.pledge.timestamp + "\ " + element.pledge.gala + "\ " + element.pledge.pledgeId + "\ " + element.pledge.type + "\ " + element.pledge.source + "\ " + PrettyPrintCurrency( element.pledge.currency , element.pledge.amount ) + "\ "); }); $("#itemized-tab-tbody").append("\ \ TOTAL\ "); $("#itemized-tab").removeClass("hide"); PopulateTotal(); } } }); $("#ways-to-pay").focus(); event.stopPropagation(); }); $("#ways-to-pay span.mdl-tabs__tab").click( function() { $("#ways-to-pay span.mdl-tabs__tab").removeClass("is-active"); $(this).addClass("is-active"); $("#ways-to-pay div.mdl-tabs__panel").removeClass("is-active"); $("#" + $(this).data("go")).addClass("is-active"); }); function PopulateTotal( guestId = "") { if ( guestId == "" ) { guestId = window.gala_guest_id; } var url = "https://api.epic.foundation/gala/guest/tab/total"; $.ajax({ url: url, dataType: "json", method: "GET", data: { guestId : guestId, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Your total pledge amount could not be retrieved. Please see a steward.", "Le total de votre promesse de dons n'a pas pu être calculée. Veuillez demander à un membre de l'équipe d'Epic.", ERROR ); } }, success: function(data, status, request , guest_id) { if ( data && (typeof data != "undefined" ) && (typeof data.guestTotal != "undefined" )) { $(".guest-pledge-total").html( PrettyPrintCurrency( window.gala_currency , data.guestTotal )); $("#ways-to-pay").removeClass("hide"); } else { $("#ways-to-pay").removeClass("hide"); $(".guest-pledge-total").html(""); } } }); } $("#logout").click( function ( event ) { location.reload(); }); $("#direct-donate > i").html("send"); $("#direct-donate").removeClass("donation-in-progress"); $("#fund-a-need-record > i").html("send"); $("#fund-a-need-record").removeClass("donation-in-progress"); $("#reconciliation-record > i").html("send"); $("#reconciliation-record").removeClass("donation-in-progress"); $("#reconciliation-record").click( function( event ) { if ( !$("#reconciliation-record").hasClass("donation-in-progress") && ($("#reconciliation-amount").html()!= "0")) { var url = "https://api.epic.foundation/gala/donate/terminal"; $("#reconciliation-record").addClass("donation-in-progress"); $("#reconciliation-record > i").html("hourglass_full"); $.ajax({ url: url, dataType: "json", method: "POST", data: { amount: $("#reconciliation-amount").html(), currency: window.gala_currency, guestId : $("#reconciliation_guest_id").html(), gala : window.gala_id, source: GetStewartId(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("The terminal payment could not be recorded.", "Le paiement par terminal n'a pu être enregistré.", ERROR ); $("#reconciliation-record").removeClass("donation-in-progress"); $("#reconciliation_guest_name").html(""); $("#reconciliation_total_pledged").html(""); $("#reconciliation_guest_id").html(""); $("#reconciliation-record > i").html("send"); } }, success: function(data, status, request , donation ) { ShowMessage("The terminal payment has been recorded.", "Le paiement par terminal a bien été enregistré", OK ); $("#reconciliation_guest_name").html(""); $("#reconciliation_total_pledged").html(""); $("#reconciliation_guest_id").html(""); $("#reconciliation").removeClass("donation-in-progress"); $("#reconciliation > i").html("send"); } }); } event.stopPropagation(); }); $("#fund-a-need-record").click( function( event ) { if ( !$("#fund-a-need-record").hasClass("donation-in-progress") && ($("#donation-amount").html()!= "0")) { var url = "https://api.epic.foundation/gala/donate"; $("#fund-a-need-record").addClass("donation-in-progress"); $("#fund-a-need-record > i").html("hourglass_full"); $.ajax({ url: url, dataType: "json", method: "POST", data: { amount: $("input[name='fund-a-need__level']:checked"). val(), currency: window.gala_currency, type: "Fund a need", guestId : $("#fund-a-need-guest").html(), gala : window.gala_id, source: GetStewartId(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("The donation could not be recorded.", "Le don n'a pu être enregistré.", ERROR ); $("#fund-a-need-record").removeClass("donation-in-progress"); $("#fund-a-need-record > i").html("send"); } }, success: function(data, status, request , donation ) { ShowMessage("The donation has been recorded.", "Le don a bien été enregistré", OK ); $("#fund-a-need-guest").html(""); $("#fund-a-need-record").removeClass("donation-in-progress"); $("#fund-a-need-record > i").html("send"); UpdateTicker(); } }); } event.stopPropagation(); }); function UpdateTicker () { $("#fund-a-need-ticker").html(""); var url = "https://api.epic.foundation/gala/donate"; $.ajax({ url: url, dataType: "json", method: "GET", data: { type: "Fund a need", access_token: GetToken() }, cache: false, error: function(object, status, error , donation ) { if ( object.statusText != 'abort' ) { ShowMessage("Ticker unavailable", "Bandeau indisponible", ERROR ); } }, success: function(data, status, request , donation ) { if ( data && (typeof data != "undefined" ) && (typeof data.pledges != "undefined" ) && (Object.keys( data.pledges ).length > 0 ) ) { $.each( data.pledges , function ( index , element) { $("#fund-a-need-ticker").append( "" + element.pledge.guestId + "" + element.pledge.amount +""); }); } } }); } $("#direct-donate").click( function( event ) { if ( !$("#direct-donate").hasClass("donation-in-progress") && ($("#donation-amount").html() != "") && ($("#donation-amount").html()!= "0")) { var url = "https://api.epic.foundation/gala/donate"; var amount = $("#donation-amount").html(); $("#direct-donate").addClass("donation-in-progress"); $("#direct-donate > i").html("hourglass_full"); $.ajax({ url: url, dataType: "json", method: "POST", donation: amount, data: { amount: amount, currency: window.gala_currency, type: "Donation", guestId : window.gala_guest_id, gala : window.gala_id, source: "0", access_token: GetToken() }, cache: false, error: function(object, status, error , donation ) { if ( object.statusText != 'abort' ) { ShowMessage("Your donation of " + $("#donation-amount").html() + "could not be recorded. Please seek assistance from an Epic steward.", "Votre donation de " + $("#donation-amount").html() + " n'a pu être enregistrée. Veuillez consulter un membre de l'équipe Epic.", ERROR ); $("#donation-amount").html(""); $("#direct-donate").removeClass("donation-in-progress"); $("#direct-donate > i").html("send"); } }, success: function(data, status, request , donation ) { ShowMessage("Your donation of " + $("#donation-amount").html() + " has been recorded.", "Votre donation de " + $("#donation-amount").html() + " a bien été enregistrée", OK ); $("#donation-amount").html(""); $("#direct-donate").removeClass("donation-in-progress"); $("#direct-donate > i").html("send"); } }); } event.stopPropagation(); }); if ( GetToken() !="" ) { LocalizeGala(); } function GetStewartId () { if (window.gala_admin_id != "" ) { return window.gala_admin_id; } else if ( window.gala_stewart_id != "") { return window.gala_stewart_id; } else { return false; } } function GetToken () { if (window.access_token != "" ) { return window.access_token; } else if ( window.stewart_access_token != "") { return window.stewart_access_token; } else if ( window.admin_access_token != "") { return window.admin_access_token; } else { return false; } } function LocalizeGala () { var url = "https://api.epic.foundation/gala"; $.ajax({ url: url, dataType: "json", method: "GET", data: { access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Some details about this gala could not be retrieved.", "Certains de&eaute;tails de ce gala n'ont pas pu être retrouvés.", ERROR ); } }, success: function(data, status, request) { if ( data && (Object.keys(data).length > 0 ) && (typeof data != "undefined" ) && (typeof data[0].gala != "undefined" ) && (typeof data[0].gala.raffleTicketAmount != "undefined" ) && (typeof data[0].gala.currency != "undefined" ) && (typeof data[0].gala.gala != "undefined" ) ) { window.gala_currency = data[0].gala.currency; window.gala_raffle_ticket_amount = data[0].gala.raffleTicketAmount; window.gala_id = data[0].gala.gala; window.gala_rsvp_total = data[0].gala.totalRSVP; $(".ticket-cost").html( PrettyPrintCurrency( data[0].gala.currency , data[0].gala.raffleTicketAmount )); $(".program").addClass("hide"); $(".program[data='" + window.gala_id + "']").removeClass("hide"); ShowMessage("You are attending the " + PrettyPrintGala( window.gala_id ) + " Epic Night 2018.", "Vous participez à l'Epic Night 2018 à " + PrettyPrintGala( window.gala_id ), INFO ); $(".gala-currency").html( PrettyPrintCurrency(window.gala_currency) ); $(".program[data-gala='" + window.gala_id + "']").removeClass("hide"); $(".activity-ticket-cost").html( PrettyPrintCurrency( window.gala_currency , window.activity_ticket_cost )); FetchAuctionItems (); } } }); } function CustomizeInterface ( type ) { var url = "https://api.epic.foundation/gala/guest"; $.ajax({ url: url, dataType: "json", method: "GET", type: type, data: { access_token: GetToken(), }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Some details on this gala could not be retrieved.", "Certains détails de ce gala n'ont pas pu être retrouvés.", ERROR ); } }, success: function(data, status, request ) { if ( data && (Object.keys(data).length > 0 ) && (typeof data != "undefined" ) && (typeof data[0].guest != "undefined" ) && (typeof data[0].guest.guestId != "undefined" ) && (typeof data[0].guest.first != "undefined" ) && (typeof data[0].guest.last != "undefined" ) ) { switch ( this.type ) { case "gala-admin": window.gala_admin_id = data[0].guest.guestId; window.gala_admin_first_name = data[0].guest.first; $(".admin-first-name").html( data[0].guest.first ); break; case "gala-stewart": window.gala_stewart_id = data[0].guest.guestId; window.gala_stewart_first_name = data[0].guest.first; $(".stewart-first-name").html( data[0].guest.first ); break; case "gala-guest": default: window.gala_guest_id = data[0].guest.guestId; window.gala_guest_first_name = data[0].guest.first; window.gala_guest_last_name = data[0].guest.last; $(".guest-first-name").html( data[0].guest.first ); $(".guest-last-name").html( data[0].guest.last ); break; } } setTimeout ( function () { $("#logout").addClass("hide"); } , 30000 ); } }); } $(".auction__link").click ( function ( event ) { if ( $("#auction_lots").html() == "") { FetchAuctionItems (); } }); function GetOrgFact ( lang ) { var selected = window.facts[ lang ][Math.floor(Math.random()*window.facts[ lang ].length)]; return selected; } function PeriodicCheckBid () { if ( (GetToken() != "") && ( window.gala_guest_id != "" ) && ( window.gala_id != "" )) { $(".auction__link > div").removeClass("mdl-badge"); $(".auction__link > div").attr("data-badge" , 0 ); $("#auction_lots .auctionItem").each( function ( index , element ) { $("#" + element.id ).removeClass("overbid"); var url = 'https://api.epic.foundation/gala/activity/auction/bid'; $.ajax({ url: url, dataType: "json", method: "GET", targetItem: element.id, data: { auctionItemId: element.id, guestId : window.gala_guest_id, gala : window.gala_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { // silent accept } }, success: function(data, status, request ) { if ( data && (typeof data != "undefined" ) && (typeof data.bids != "undefined" ) && (Object.keys(data.bids).length > 0) && (typeof data.bids[0].bid != "undefined" ) && (typeof data.bids[0].bid.bidAmount == "number" ) && (typeof data.bids[0].bid.topBid == "number" ) && (data.bids[0].bid.bidAmount < data.bids[0].bid.topBid ) ) { $("#" + this.targetItem ).addClass("overbid"); NotifyNoLongerHighestBidder(); } } }); }); } } setInterval( PeriodicCheckBid , 30000); setInterval( PeriodicCheckAuction , 65000); function PeriodicCheckAuction () { // Don't refresh the auction if the tab is visible if ( !$("#auction").hasClass("is-active") && ( GetToken()!="") && (window.gala_id != "" )) { FetchAuctionItems (); } } function NotifyNoLongerHighestBidder() { $(".auction__link > div").addClass("mdl-badge"); if ( $(".auction__link > div").attr("data-badge") === undefined ) { $(".auction__link > div").attr("data-badge" , 0 ); } $(".auction__link > div").attr("data-badge" , parseInt($(".auction__link > div").attr("data-badge")) + 1 ); ShowMessage("Someone is bidding higher than you at the silent auction", "Votre enchère a été dépassée !" , ERROR ); } function ClearNoLongerHighestBidderNotifications () { $(".auction__link > div").removeClass("mdl-badge"); $(".auction__link > div").attr("data-badge" , 0); } function AddThousandSeparator ( nStr , separator ) { nStr += ''; x = nStr.split('.'); x1 = x[0]; x2 = x.length > 1 ? '.' + x[1] : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + separator + '$2'); } return x1 + x2; } function PrettyPrintCurrency ( currency , amount = "") { switch ( currency ) { case "GBP": return "£" + AddThousandSeparator(amount.toString() , ","); break; case "EUR": return AddThousandSeparator(amount.toString(),".") + "€"; break; case "USD": default: return "$" + AddThousandSeparator(amount.toString(), ","); break; } } function PrettyPrintGala ( gala ) { switch ( gala ) { case "SF": return "San Francisco"; break; case "NY": return "New York"; break; case "PA": return "Paris"; break; case "LO": return "London"; break; case "BR": return "Brussels"; break; default: return ""; break; } } function AdminFetchLiveAuctionItems () { $("#auctionItems").html(""); var url = 'https://api.epic.foundation/gala/activity/auction'; $.ajax({ url: url, dataType: "json", method: "GET", data: { gala: window.gala_id, type: "Live", access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not load auction items: " + status + " (code: " + error + ")", "Impossible de charger les lots des enchères : " + status + " (code: " + error + ")", ERROR ); } }, success: function(data, status, request) { AddAdminLiveAuctionItems( data ); } }); } function FetchAuctionItems () { $("#auctionItems").html(""); var url = 'https://api.epic.foundation/gala/activity/auction'; $.ajax({ url: url, dataType: "json", method: "GET", data: { gala: window.gala_id, type: "Silent", access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not load auction items: " + status + " (code: " + error + ")", "Impossible de charger les lots des enchères : " + status + " (code: " + error + ")", ERROR ); } }, success: function(data, status, request) { AddAuctionItems( data ); } }); } function FetchAdminAuctionItems () { $("#auction-activation").html(""); var url = 'https://api.epic.foundation/gala/activity/auction'; $.ajax({ url: url, dataType: "json", method: "GET", data: { gala: window.gala_id, type: "Silent", access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not load auction items: " + status + " (code: " + error + ")", "Impossible de charger les lots des enchères : " + status + " (code: " + error + ")", ERROR ); } }, success: function(data, status, request) { AddAdminAuctionItems( data ); } }); } $("#send-thank-you-email").click( function ( event ) { var url = 'https://api.epic.foundation/gala/guest/nextday'; $.ajax({ url: url, dataType: "json", method: "POST", data: { gala: window.gala_id, epic_lang: "en", access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Failed to initiate email batch.", "Impossible de lancer le batch d'emails.", ERROR ); } }, success: function(data, status, request) { ShowMessage("Email batch launched.", "Batch d'emails initié.", OK ); } }); }); function SetStatusAuctionItem ( auctionItemId , isLive ) { var url = 'https://api.epic.foundation/gala/activity/auction/status'; $.ajax({ url: url, dataType: "json", method: "POST", live: isLive, itemId: auctionItemId, data: { auctionItemId: auctionItemId, isLive: isLive, gala: window.gala_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not load set the status of auction item: " + this.auctionItemId + " to " + this.live + " : " + status + " (code: " + error + ")", "Impossible de donner au lot d'enchère : " + this.auctionItemId + " le statut " + this.live + " : " + status + " (code: " + error + ")", ERROR ); } }, success: function(data, status, request) { ShowMessage("Update completed.", "Mise à jour effectuée.", OK ); } }); } $("#auction-activation").on("click" , ".auctionActivation input[type='checkbox']" ,function () { var isChecked = $(this).is(":checked"); if ( isChecked ) { SetStatusAuctionItem ( $(this).data("id") , "Y" )} else { SetStatusAuctionItem ( $(this).data("id") , "N") } }); $("#auction-activation-all-off").click( function () { $("#auction-activation .auction-activation-checkbox").each( function ( index, element ) { SetStatusAuctionItem ( $(this).data("id") , "N"); }); }); $("#auction-activation-convert").click( function ( event ) { $("#auction-activation-convert").addClass("mdl-button--disabled"); var url = 'https://api.epic.foundation/gala/activity/auction/convert'; $.ajax({ url: url, dataType: "json", method: "POST", data: { type: "Silent", gala: window.gala_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not convert the highest bids of silent auction items into pledge.", "Impossible de convertir les meilleures offres d'enchères silencieuses en dons.", ERROR ); $("#auction-activation-convert").removeClass("mdl-button--disabled"); } }, success: function(data, status, request) { ShowMessage("Conversion completed.", "Conversion effectuée.", OK ); ShowListOfAuctionWinners( data ); $("#auction-activation-convert").removeClass("mdl-button--disabled"); } }); }); function ShowListOfAuctionWinners ( data ) { $("#auction-winners-list").html(""); if ( (typeof data !== "undefined" ) && (data && Object.keys(data).length > 0) && (typeof data.winners !== "undefined" ) && (data && Object.keys(data.winners).length > 0) ) { $.each( data.winners , function ( index , element) { $("#auction-winners-list").append("\ \ \ " + element.french + "\ \ \ " + element.english + "\ \ \ " + element.winnerName +"\ \ \ " + element.winnerId + "\ \ \ " + PrettyPrintCurrency( element.winningBidCurrency , element.winningBidAmount ) + "\ \ \ "); }); componentHandler.upgradeDom(); epic_UpdateLanguage( $("html").attr("lang") , false ); } } function AddAdminAuctionItems ( data ) { if ( data && Object.keys(data).length > 0 ) { $("#auction-activation").html(""); $.each( data.auctionItems , function ( index , element) { var block = "
\
"; $("#auction-activation").append( block ); }); componentHandler.upgradeDom(); epic_UpdateLanguage( $("html").attr("lang") , false ); } } function AddAuctionItems ( data ) { if ( data && Object.keys(data).length > 0 ) { $("#auction_lots").html(""); $.each( data.auctionItems , function ( index , element) { $("#auction_lots").append("
\
\

"+ element.auctionItem.title_fr + "

\

"+ element.auctionItem.title_en + "

\
\
\ \
\
\ "+ element.auctionItem.description_fr + "\
\
\ "+ element.auctionItem.description_en + "\
\
\
"); if ( (element.auctionItem.type == "Silent") && (element.auctionItem.isLive == "Y") ) { $("#" + element.auctionItem.auctionItemId + " .mdl-card__actions").append("\ Faire une offre\ Bid now\ "); } else if ( ( element.auctionItem.type == "Silent") && ( element.auctionItem.isLive == "N") && ( element.auctionItem.gala == window.gala_id ) ) { $("#" + element.auctionItem.auctionItemId + " .mdl-card__actions").append("\ Silent auction not open\ Enchère silencieuse suspendue\ "); } else if ( (element.auctionItem.type == "Live" ) && ( element.auctionItem.gala == window.gala_id )) { $("#" + element.auctionItem.auctionItemId + " .mdl-card__actions").append("\ A suivre en direct\ Live auction lot\ "); } else { $("#" + element.auctionItem.auctionItemId + " .mdl-card__actions").append("\ Enchère indisponible\ Lot unavailable tonight\ "); } }); } else if ( typeof data != "undefined" && typeof data.error == "undefined" ) { // no results ShowMessage("No auction lots!", "Aucun lot!", OK ); } else { ShowMessage("An error occurred.", "Une erreur a été détectée", ERROR ); } //we introduced new elements on the page: show those in the correct language epic_UpdateLanguage( $("html").attr("lang") , false ); } function AddAdminLiveAuctionItems ( data ) { if ( data && Object.keys(data).length > 0 ) { $("#list-of-live-auction-items").html(""); $.each( data.auctionItems , function ( index , element) { $("#list-of-live-auction-items").append("
\
\

"+ element.auctionItem.title_fr + "

\

"+ element.auctionItem.title_en + "

\
\
\
"); $("#ATTRIB_" + element.auctionItem.auctionItemId + " .mdl-card__actions").append("\ Entrer l'enchère gagnante\ Enter winning auction\ "); }); epic_UpdateLanguage( $("html").attr("lang") , false ); } else if ( typeof data != "undefined" && typeof data.error == "undefined" ) { // no results ShowMessage("No live auction lots!", "Aucun lot!", OK ); } else { ShowMessage("An error occurred.", "Une erreur a été détectée", ERROR ); } } $("#list-of-live-auction-items").on("click" , ".enter-winner" , function () { $("#overlay_auction_winner_bid_wrapper").removeClass("hide"); $("#gala_obfuscator").addClass("is-visible"); $("#winning-id").focus(); $("#winning-id").select(); $("#winning-item-id").html( $(this).closest(".auctionItem").children("div.mdl-card__actions").first().data("item")); $("#winning-item-description span[lang='en']").html( $(this).closest(".auctionItem").find(".mdl-card__title h2.mdl-card__title-text[lang='en']").first().html()); $("#winning-item-description span[lang='fr']").html( $(this).closest(".auctionItem").find(".mdl-card__title h2.mdl-card__title-text[lang='fr']").first().html()); epic_UpdateLanguage( $("html").attr("lang") , false ); }); $("#auction_lots").on("click" , ".bid-now" , function () { GetBid( $(this).closest(".mdl-card__actions").data("item") ); }); $("#overlay_auction_bid_wrapper").click( function () { $("#overlay_auction_bid_wrapper").addClass("hide"); $("#gala_obfuscator").removeClass("is-visible"); }); $("#overlay_auction_winner_bid_wrapper").click( function () { $("#overlay_auction_winner_bid_wrapper").addClass("hide"); $("#gala_obfuscator").removeClass("is-visible"); }); $("#new-bid, #confirm-bid, #overlay_auction_bid, #overlay_auction_winner_bid").click( function ( event ) { event.stopPropagation(); }); function GetBid ( itemId ) { var url = 'https://api.epic.foundation/gala/activity/auction/bid'; $.ajax({ url: url, dataType: "json", method: "GET", targetItem: itemId, data: { auctionItemId: itemId, guestId : window.gala_guest_id, gala : window.gala_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Bid information could not be retrieved.", "Les enchères sur ce lot ne sont pas disponibles.", ERROR ); $("#overlay_auction_bid_wrapper").addClass("hide"); } }, success: function(data, status, request ) { $("#new-bid").data("item" , this.targetItem ); $("#has-not-bidded-yet,#current_bid,#warning_lower_bid_entered,#warning_under_reserve_entered").addClass("hide"); $("#new-bid").val("") ; $(".current-bid-amount-overlay").data("amount" , 0 ); $(".current-bid-amount-overlay").html( "0" ); $(".current-top-bid-amount-overlay").data("amount" , 0 ); $(".current-top-bid-amount-overlay").html( "0" ); $('#confirm-bid').addClass("mdl-button--disabled"); if ( data && (typeof data != "undefined" ) && (typeof data.bids != "undefined" ) && (Object.keys(data.bids).length > 0) && (typeof data.bids[0].bid != "undefined" ) && (typeof data.bids[0].bid.bidAmount != "undefined" ) ) { $("#current_bid").html(); $(".reserve-bid").html(); console.log($("#" + this.targetItem).data("reserve")); if (( $("#" + this.targetItem).data("reserve") != null) && ( $("#" + this.targetItem).data("reserve") != 0) ) { $(".reserve-bid").html( PrettyPrintCurrency( data.bids[0].bid.reserveBidCurrency , $("#" + this.targetItem).data("reserve"))); } else { $(".reserve-bid").html( PrettyPrintCurrency( window.gala_currency , 0 )); } if ( data.bids[0].bid.bidAmount != null ) { // guest has an active bid $(".current-bid-amount-overlay").html( PrettyPrintCurrency( data.bids[0].bid.currency , data.bids[0].bid.bidAmount ) ); $("#current_bid").removeClass("hide"); $("#has-not-bidded-yet").addClass("hide"); } else { $("#current_bid").addClass("hide"); $("#has-not-bidded-yet").removeClass("hide"); } if ( data.bids[0].bid.topBid != null ) { // show top bid $(".current-top-bid-amount-overlay").html( PrettyPrintCurrency( data.bids[0].bid.currency , data.bids[0].bid.topBid ) ); $("#current_top_bid").removeClass("hide"); $("#zero-bids-yet").addClass("hide"); } else { $("#current_top_bid").addClass("hide"); $("#zero-bids-yet").removeClass("hide"); } } else { $("#current_top_bid").addClass("hide"); $("#zero-bids-yet").removeClass("hide"); $(".reserve-bid").html(); console.log($("#" + this.targetItem).data("reserve")); if (( $("#" + this.targetItem).data("reserve") != null) && ( $("#" + this.targetItem).data("reserve") != 0) ) { $(".reserve-bid").html( PrettyPrintCurrency( window.gala_currency , $("#" + this.targetItem).data("reserve"))); } else { $(".reserve-bid").html( PrettyPrintCurrency( window.gala_currency , 0 )); } } $("#overlay_auction_bid_wrapper").removeClass("hide"); $("#gala_obfuscator").addClass("is-visible"); $("#new-bid").focus(); $("#new-bid").select(); } }); } $("#new-bid").keyup ( function ( event ) { var charCode = (event.which) ? event.which : event.keyCode; if (!((charCode >= 48 && charCode <= 57) || (charCode == 8) || (charCode == 127) )) { event.preventDefault(); return false; } if ( $("#new-bid").val() != "" ) { if ( parseInt($("#new-bid").val()) <= parseInt($(".current-top-bid-amount-overlay").html().replace( /[^0-9]+/g, ''))) { $('#confirm-bid').addClass("mdl-button--disabled"); $("#warning_lower_bid_entered").removeClass("hide"); } else if (parseInt($("#new-bid").val()) < parseInt($(".reserve-bid").html().replace( /[^0-9]+/g, ''))) { $('#confirm-bid').addClass("mdl-button--disabled"); $("#warning_under_reserve_entered").removeClass("hide"); } else { $('#confirm-bid').removeClass("mdl-button--disabled"); $("#warning_lower_bid_entered,#warning_under_reserve_entered").addClass("hide"); } } else { $('#confirm-bid').addClass("mdl-button--disabled"); $("#warning_lower_bid_entered,#warning_under_reserve_entered").addClass("hide"); } }); $("#confirm-winning-bid").click ( function ( event ) { if ( $("#confirm-winning-bid").hasClass("mdl-button--disabled")) { event.stopPropagation(); return false; } $("#overlay_auction_winner_bid_wrapper").addClass("hide"); $("#gala_obfuscator").removeClass("is-visible"); var url = 'https://api.epic.foundation/gala/donate'; $.ajax({ url: url, dataType: "json", method: "POST", data: { amount: $("#winning-bid").val(), currency: window.gala_currency, type: "Live Auction", guestId : $("#winning-id").val(), gala : window.gala_id, source: $("#winning-item-id").html(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { if ( ( typeof object.responseJSON != "undefined") && ( typeof object.responseJSON.error != "undefined" ) ) { ShowMessage( "The auction win could not be recorded " + object.responseJSON.error , "Impossible d'enregistrer le gagnant de l'enchère: Une erreur a été détectée: " + object.responseJSON.error , ERROR ); } else { ShowMessage("The winner could not be recorded.", "Impossible d'enregistrer l'enchère gagnante.", ERROR ); } $("#winning-bid").val(""); $("#winning-item-id").html(""); } }, success: function(data, status, request) { ShowMessage("Auction win recorded.", "Enchère gagnante enregistrée.", OK ); } }); }); $("#add-donation-to-pledge").click ( function ( event ) { var url = 'https://api.epic.foundation/gala/donate'; $.ajax({ url: url, dataType: "json", method: "POST", data: { amount: $("#confirmed-payment-amount").val(), currency: window.gala_currency, type: "Processed payment", guestId : $("#confirmed-payment-guest-id").val(), gala : window.gala_id, source: "0", access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { if ( ( typeof object.responseJSON != "undefined") && ( typeof object.responseJSON.error != "undefined" ) ) { ShowMessage( "The confirmed payment could not be recorded " + object.responseJSON.error , "Impossible d'enregistrer le paiement confirmé. Une erreur a été détectée: " + object.responseJSON.error , ERROR ); } else { ShowMessage("The confirmed payment could not be recorded.", "Impossible d'enregistrer le paiement confirmé.", ERROR ); } $("#confirmed-payment-amount").val(""); $("#confirmed-payment-guest-id").val(""); } }, success: function(data, status, request) { ShowMessage("Confirmed payment recorded.", "Paiement confirmé enregistré.", OK ); $("#confirmed-payment-amount").val(""); $("#confirmed-payment-guest-id").val(""); $("#confirmed-payment-amount").focus(); $("#confirmed-payment-amount").select(); } }); }); $("#send-payment-email").click ( function (event ) { var url = 'https://api.epic.foundation/gala/guest/tab/batch'; $.ajax({ url: url, dataType: "json", method: "POST", data: { receipt: $("#payment-details-type option:selected").val(), epic_lang: $("#payment-details-language option:selected").val(), gala : window.gala_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("The batch could not be started because of a connectivity issue.", "Le batch d'email n'a pas pu être envoyé à cause d'un problème de connexion.", ERROR ); $("#gala_obfuscator").removeClass("is-visible"); $("#email-centralizer").addClass("hide"); } }, success: function(data, status, request) { if ( data && Object.keys(data).length > 0 && typeof data != "undefined" && typeof data.status != "undefined" && data.status == "OK" ) { ShowMessage("The email batch was started with " + data.counter + " emails.", "Le batch d'email a été initié avec " + data.counter + " emails.", OK ); $("#gala_obfuscator").removeClass("is-visible"); $("#email-centralizer").addClass("hide"); } else { ShowMessage("The email batch could not be started.", "Le batch d'email n'a pas pu être initié.", ERROR ); $("#gala_obfuscator").removeClass("is-visible"); $("#email-centralizer").addClass("hide"); } } }); }); $("#add-pregala-pledge").click ( function ( event ) { var url = 'https://api.epic.foundation/gala/donate'; $.ajax({ url: url, dataType: "json", method: "POST", data: { amount: $("#pregala-pledge-amount").val(), currency: window.gala_currency, type: "Pledged at Registration", guestId : $("#pregala-pledge-guest-id").val(), gala : window.gala_id, source: "0", access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { if ( ( typeof object.responseJSON != "undefined") && ( typeof object.responseJSON.error != "undefined" ) ) { ShowMessage( "The pre-gala pledge could not be recorded " + object.responseJSON.error , "Impossible d'enregistrer la promesse de don lors du RSVP. Une erreur a été détectée: " + object.responseJSON.error , ERROR ); } else { ShowMessage("The pre-gala pledge could not be recorded.", "Impossible d'enregistrer la promesse de don lors du RSVP.", ERROR ); } $("#pregala-pledge-amount").val(""); $("#pregala-pledge-guest-id").val(""); } }, success: function(data, status, request) { ShowMessage("Confirmed payment recorded.", "Paiement confirmé enregistré.", OK ); $("#pregala-pledge-amount").val(""); $("#pregala-pledge-guest-id").val(""); $("#pregala-pledge-amount").focus(); $("#pregala-pledge-amount").select(); } }); }); $("#confirm-bid").click ( function ( event ) { if ( $("#confirm-bid").hasClass("mdl-button--disabled")) { event.stopPropagation(); return false; } $("#overlay_auction_bid_wrapper").addClass("hide"); $("#gala_obfuscator").removeClass("is-visible"); var url = 'https://api.epic.foundation/gala/activity/auction/bid'; $.ajax({ url: url, dataType: "json", method: "POST", data: { auctionItemId: $("#new-bid").data("item"), guestId: window.gala_guest_id, gala: window.gala_id, currency: window.gala_currency, bidAmount: $("#new-bid").val(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { if ( ( typeof object.responseJSON != "undefined") && ( typeof object.responseJSON.error != "undefined" ) ) { ShowMessage( "Your bid could not be recorded " + object.responseJSON.error , "Impossible d'enregistrer votre enchère: Une erreur a été détectée: " + object.responseJSON.error , ERROR ); } else { ShowMessage("Your bid could not be recorded.", "Impossible d'enregistrer votre enchère.", ERROR ); } } }, success: function(data, status, request) { if ( data && (typeof data != "undefined" ) && (typeof data.bids != "undefined" ) && (Object.keys(data.bids).length > 0) && (typeof data.bids[0].bid != "undefined" ) && (typeof data.bids[0].bid.bidAmount != "undefined" ) && (typeof data.bids[0].bid.currency != "undefined" ) ) { ShowMessage("Your bid of " + PrettyPrintCurrency( data.bids[0].bid.currency , data.bids[0].bid.bidAmount) + " has been recorded.", "Votre enchère de " + PrettyPrintCurrency( data.bids[0].bid.currency , data.bids[0].bid.bidAmount) + " a été prise en compte.", OK ); } } }); }); function ResetLogin() { $("#login_identifier").html(""); } $("#purchase-raffle-tickets").click( function ( event ) { var url = 'https://api.epic.foundation/gala/activity/raffle/play'; for ( i=1 ; i <= $("#raffle-purchase-wrapper input[type='range']").val() ; i++ ) { $.ajax({ url: url, dataType: "json", method: "POST", data: { currency: window.gala_currency, amount: window.gala_raffle_ticket_amount, gala: window.gala_id, guestId: window.gala_guest_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not purchase raffle ticket.", "Impossible d'acheter le ticket.", ERROR ); } }, success: function(data, status, request) { if ( data && typeof data != "undefined" && Object.keys(data).length > 0 && typeof data.tickets != "undefined" && Object.keys(data.tickets).length > 0 && typeof data.tickets[0].ticket != "undefined" && typeof data.tickets[0].ticket.ticketId != "undefined" ) { $("#spin-the-wheel").data("next" , data.tickets[0].ticket.ticketId ); $("#spin-the-wheel").removeClass("mdl-button--disabled"); $("#wheel").removeClass("hide"); } else { ShowMessage("An connectivity error occurred. Your tickets were not purchased.", "Une erreur de connexion a été détectée. Vos billets n'ont pas été achetés.", ERROR ); } } }); } }); $("#purchase-activity-tickets").click( function ( event ) { $(".activity__link > div").addClass("mdl-badge"); if( $(".activity__link > div").attr("data-badge") == "" ) { $(".activity__link > div").attr("data-badge", "0"); } $("#purchase-activity-tickets").addClass("mdl-button--disabled"); var url = 'https://api.epic.foundation/gala/donate'; for ( i=1 ; i <= $("#activity-purchase-wrapper input[type='range']").val() ; i++ ) { $(".activity__link > div").attr("data-badge" , parseInt($(".activity__link > div").attr("data-badge")) + 1 ); var url = "https://api.epic.foundation/gala/donate"; $.ajax({ url: url, dataType: "json", method: "POST", data: { amount: window.activity_ticket_cost, currency: window.gala_currency, type: "Soccer Booth", guestId : window.gala_guest_id, gala : window.gala_id, source: GetStewartId(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Your donation could not be recorded.", "Le don n'a pu être enregistré.", ERROR ); } }, success: function(data, status, request , donation ) { ShowMessage("The donation has been recorded.", "Le don a bien été enregistré", OK ); } }); } $("#purchase-activity-tickets").removeClass("mdl-button--disabled"); event.stopPropagation(); }); $("#spin-the-wheel").click(function(){ if ( !$(this).hasClass("mdl-button--disabled")) { // disable spin $('#spin-the-wheel').addClass("mdl-button--disabled"); $("#wheel svg circle, #wheel").addClass("active-wheel"); totalDegree = Math.floor((Math.random() * 7200) + 1); $('#wheel').css({'transform' : 'rotate(' + totalDegree + 'deg)'}); setTimeout( UpdatedProcessDraw , 6500 ); } }); function UpdatedProcessDraw () { $("#gala_obfuscator").addClass("is-visible"); $("#facts-centralizer").removeClass("hide"); $("#org-fact p > span[lang='en']").html( GetOrgFact("en")); $("#org-fact p > span[lang='fr']").html( GetOrgFact("fr")); setTimeout( function () { $("#facts-centralizer").addClass("hide"); $("#gala_obfuscator").removeClass("is-visible"); } , 10000 ); } //a click outside of the guest selection drowdown aborts the selection $("body").click( function () { $("#search_guest_results,#audit_search_guest_results,#reconciliation_search_guest_results").html(""); $("#audit_search_guest_results,#search_guest_results,#reconciliation_search_guest_results").addClass("hide"); $("#audit_trail__body").html(""); }); // $("#searchguest").click( function ( event ){ // // if ( $("#search_guest_input").val() != "" ) // { // FetchGuests(); // event.stopPropagation(); // } //}); //$("#auditsearchguest").click( function ( event ){ // // if ( $("#audit_search_guest_input").val() != "" ) // { // FetchAuditGuests(); // event.stopPropagation(); // } //}); // $("#auditsearchguest").click( function ( event ){ // // if ( $("#audit_search_guest_input").val() != "" ) // { // FetchAuditGuests(); // event.stopPropagation(); // } //}); // retrieves possible matches for a guest function FetchGuests () { $("#search_guest_results").html(""); var url = 'https://api.epic.foundation/gala/guest/search'; window.ajaxGuestSearchObj = $.ajax({ url: url, dataType: "json", method: "GET", data: { search: $("#search_guest_input").val(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not load matches: " + status + " (code: " + error + ")", "Impossible d'effectuer la recherche: " + status + " (code: " + error + ")", ERROR ); } }, success: function(data, status, request) { SuggestGuests( data ); } }); } function UpdateProbability () { var url = 'https://api.epic.foundation/gala/activity/raffle/count'; $.ajax({ url: url, dataType: "json", method: "GET", data: { gala : window.gala_id, source: GetStewartId(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("The probability could not be updated.", "La probabilité n'a pas pu être mise à jour", ERROR ); } }, success: function(data, status, request , donation ) { if ( data && (typeof data != "undefined" ) && (typeof data.tickets != "undefined" ) ) { if ( parseInt(data.tickets) > 0 ) { var probability = ((1/parseInt(data.tickets))*100).toFixed(2) + "%"; } else { var probability = "100%"; } $("#probability").html( probability ); $("#total-number-of-eligible-tickets").html( data.tickets ); } } }); } $("#refresh-stats").click( function ( event ) { UpdateCounters(); event.stopPropagation(); }); $("#refresh-auction-winner").click( function ( event ) { AdminFetchLiveAuctionItems(); event.stopPropagation(); }); function UpdateCounters () { var url = 'https://api.epic.foundation/gala/scoreboard'; $.ajax({ url: url, dataType: "json", method: "GET", data: { gala : window.gala_id, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("The counters could not be updated.", "Les compteurs n'ont pas pu être mise à jour", ERROR ); } }, success: function(data, status, request , donation ) { if ( data && (typeof data != "undefined" ) && (typeof data.attendees != "undefined" ) && (typeof data.pledgers != "undefined" ) && (typeof data.percentage != "undefined" ) ) { $("#admin tr.refreshable").remove(); $("#gala-headcount").html( data.attendees ); if ( window.gala_rsvp_total != 0 ) { $("#gala-headcount-percentage").html( ((data.attendees / window.gala_rsvp_total)*100).toFixed(2) + "%"); } else { $("#gala-headcount-percentage").html(""); } $("#gala-pledgers-count").html( data.pledgers ); $("#gala-pledgers-percentage").html( data.percentage.toFixed(2) + "%"); $.each( data.pledges , function ( index , element) { $("#admin-table-body").append( "" + element.type +"" + PrettyPrintCurrency( element.currency, element.total ) + ""); }); $.each( data.auctions , function ( index , element) { $("#admin-table-body").append( "" + element.french +"" + element.english +"" + PrettyPrintCurrency( element.currency, element.amount ) + ""); }); epic_UpdateLanguage( $("html").attr("lang") , false ); } } }); } $("#choose-raffle-winner").click( function ( event ) { $("#choose-raffle-winner").addClass("mdl-button--disabled"); var url = 'https://api.epic.foundation/gala/activity/raffle/winner'; $.ajax({ url: url, dataType: "json", method: "GET", data: { gala : window.gala_id, source: GetStewartId(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("A winner could not be selected.", "Aucun gagnant.", ERROR ); setTimeout( function () { $("#choose-raffle-winner").removeClass("mdl-button--disabled"); } , 10000 ); } }, success: function(data, status, request , donation ) { ShowMessage("Winner chosen!", "Un gagnant a bien été choisi", OK ); if ( data && (typeof data != "undefined" ) && (typeof data.FIRST_NAME != "undefined" ) && (typeof data.LAST_NAME != "undefined" ) ) { $("#winner-name").html( data.FIRST_NAME + " " + data.LAST_NAME + "(" + data.GUEST_ID + ")"); $("#winner-number").html( data.TICKET_ID); setTimeout( function () { $("#choose-raffle-winner").removeClass("mdl-button--disabled"); } , 10000 ); } } }); }); // retrieves possible matches for a guest function FetchAuditGuests () { $("#search_guest_results").html(""); var url = 'https://api.epic.foundation/gala/guest/search'; window.ajaxAuditGuestSearchObj = $.ajax({ url: url, dataType: "json", method: "GET", data: { search: $("#audit_search_guest_input").val(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not load matches: " + status + " (code: " + error + ")", "Impossible d'effectuer la recherche: " + status + " (code: " + error + ")", ERROR ); } }, success: function(data, status, request) { SuggestAuditGuests( data ); } }); } // retrieves possible matches for a guest function FetchReconcileGuests () { $("#search_guest_results").html(""); var url = 'https://api.epic.foundation/gala/guest/search'; window.ajaxAuditGuestSearchObj = $.ajax({ url: url, dataType: "json", method: "GET", data: { search: $("#reconciliation_search_guest_input").val(), access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("Could not load matches: " + status + " (code: " + error + ")", "Impossible d'effectuer la recherche: " + status + " (code: " + error + ")", ERROR ); } }, success: function(data, status, request) { SuggestReconcileGuests( data ); } }); } //focus on the field selects it all $("#search_guest_input").on("click", function () { $(this).select(); if ( $("#search_guest_input").val() != "" ) { FetchGuests(); } }); //focus on the field selects it all $("#audit_search_guest_input").on("click", function () { $("#audit_trail__body").html(""); $(this).select(); if ( $("#audit_search_guest_input").val() != "" ) { FetchAuditGuests(); } }); //focus on the field selects it all $("#reconciliation_search_guest_input").on("click", function () { $(this).select(); if ( $("#reconciliation_search_guest_input").val() != "" ) { FetchReconcileGuests(); } }); //dynamic typing of name queries $("#search_guest_input").keyup( function (){ if ( typeof window.ajaxGuestSearchObj == "object" ) { window.ajaxGuestSearchObj.abort(); window.ajaxGuestSearchObj = undefined; } if ( $("#search_guest_input").val() != "" ) { FetchGuests(); } else { $("#search_guest_results").addClass("hide"); $("#search_guest_input").data( "guestid" , ""); } $("#addguest").addClass("hide"); $("#addguest input").val(""); $("#guest_name").html(""); $("#guest_id").html(""); }); //dynamic typing of name queries $("#audit_search_guest_input").keyup( function (){ $("#audit_trail__body").html(""); if ( typeof window.ajaxAuditGuestSearchObj == "object" ) { window.ajaxAuditGuestSearchObj.abort(); window.ajaxAuditGuestSearchObj = undefined; } if ( $("#audit_search_guest_input").val() != "" ) { FetchAuditGuests(); } else { $("#audit_search_guest_results").addClass("hide"); $("#audit_search_guest_input").data( "guestid" , ""); } $("#audit_guest_name").html(""); $("#audit_guest_id").html(""); }); //dynamic typing of name queries $("#reconciliation_search_guest_input").keyup( function (){ $("#audit_trail__body").html(""); if ( typeof window.ajaxReconcileGuestSearchObj == "object" ) { window.ajaxReconcileGuestSearchObj.abort(); window.ajaxReconcileGuestSearchObj = undefined; } if ( $("#reconciliation_search_guest_input").val() != "" ) { FetchReconcileGuests(); } else { $("#reconciliation_search_guest_results").addClass("hide"); $("#reconciliation_search_guest_results").data( "guestid" , ""); } $("#reconciliation_guest_name").html(""); $("#reconciliation_guest_id").html(""); }); //clear-up the guest $("#searchguest").data( "guestid" , ""); $("#auditsearchguest").data( "guestid" , ""); // presents the suggestions of retrieved guests function SuggestGuests ( data ) { $("#search_guest_results").html(""); if ( data && Object.keys(data).length > 0 ) { $("#search_guest_results").removeClass("hide"); $.each( data.guests , function ( index , element) { $("#search_guest_results").append("
emailoffline_bolt" + element.guest.first + " " + element.guest.last + "
"); }); } else if ( typeof data != "undefined" && typeof data.error == "undefined" ) { // no results ShowMessage("No matching guests!", "Aucun résultat!", OK ); $("#addguest").removeClass("hide"); } else { ShowMessage("An error occurred.", "Une erreur a été détectée", ERROR ); } } // presents the suggestions of retrieved guests function SuggestAuditGuests ( data ) { $("#audit_search_guest_results").html(""); if ( data && Object.keys(data).length > 0 ) { $("#audit_search_guest_results").removeClass("hide"); $.each( data.guests , function ( index , element) { $("#audit_search_guest_results").append("
" + element.guest.first + " " + element.guest.last + "
"); if ( element.guest.active == "Y") { $("div.guest[data-guestid='" + element.guest.guestId + "']").addClass("is-already-active"); } if ( element.guest.locked == "Y") { $("div.guest[data-guestid='" + element.guest.guestId + "']").addClass("is-locked"); } }); } else if ( typeof data != "undefined" && typeof data.error == "undefined" ) { // no results ShowMessage("No matching guests!", "Aucun résultat!", OK ); } else { ShowMessage("An error occurred.", "Une erreur a été détectée", ERROR ); } } // presents the suggestions of retrieved guests function SuggestReconcileGuests ( data ) { $("#reconciliation_search_guest_results").html(""); if ( data && Object.keys(data).length > 0 ) { $("#reconciliation_search_guest_results").removeClass("hide"); $.each( data.guests , function ( index , element) { $("#reconciliation_search_guest_results").append("
" + element.guest.first + " " + element.guest.last + "
"); if ( element.guest.active == "Y") { $("div.guest[data-guestid='" + element.guest.guestId + "']").addClass("is-already-active"); } if ( element.guest.locked == "Y") { $("div.guest[data-guestid='" + element.guest.guestId + "']").addClass("is-locked"); } }); } else if ( typeof data != "undefined" && typeof data.error == "undefined" ) { // no results ShowMessage("No matching guests!", "Aucun résultat!", OK ); } else { ShowMessage("An error occurred.", "Une erreur a été détectée", ERROR ); } } // a click on a suggestion selects it, clears the suggestions. $("#search_guest_results").on("click", ".guest" , function ( event ) { if ( $(event.target).closest(".guest").data("guestid") != undefined ) { if ( $(event.target).closest('.guest').data("email") !== "" ) { $("#guest_name").html( $(event.target).closest('.guest').html()); $("#guest_id").html( $(event.target).closest('.guest').data("guestid")); $("#guest_id_wrapper").removeClass("hide"); $("#search").addClass("hide"); $("#search_guest_input").val(""); $("#search_guest_results").html(""); $("#search_guest_results").addClass("hide"); $("#activate-guest").removeClass("mdl-button--disabled"); } else { $("#addguest .mdl-textfield").addClass("is-dirty"); $("#addguest .mdl-textfield").has(".mdl-textfield__input[type='email']").removeClass("is-dirty"); $("#add-firstname").val( $(event.target).closest('.guest').data("firstname") ); $("#add-lastname").val( $(event.target).closest('.guest').data("lastname") ); $("#add-id").val( $(event.target).closest('.guest').data("guestid") ); $("#guest_name").html(""); $("#search").removeClass("hide"); $("#guest_id").html(""); $("#guest_id_wrapper").addClass("hide"); $("#search_guest_input").removeClass("guest-selected"); $("#search_guest_input").val(""); $("#search_guest_results").html(""); $("#search_guest_results").addClass("hide"); $("#activate-guest").addClass("mdl-button--disabled"); $("#addguest").removeClass("hide"); $("#add-email").focus(); } } else { $("#guest_name").html(""); $("#search").removeClass("hide"); $("#guest_id").html(""); $("#guest_id_wrapper").addClass("hide"); $("#search_guest_input").removeClass("guest-selected"); $("#search_guest_input").val(""); $("#search_guest_results").html(""); $("#search_guest_results").addClass("hide"); $("#activate-guest").addClass("mdl-button--disabled"); } event.stopPropagation(); }); $("#audit_search_guest_results").on("click", ".guest" , function ( event ) { if ( $(event.target).closest(".guest").data("guestid") != undefined ) { $("#audit_guest_name").html( $(event.target).closest('.guest').html()); $("#audit_guest_id").html( $(event.target).closest('.guest').data("guestid")); $("#audit_guest_id_wrapper").removeClass("hide"); $("#audit_search_guest_input").val(""); $("#audit_search_guest_results").html(""); $("#audit_search_guest_results").addClass("hide"); FetchAuditTrail( $("#audit_guest_id").html()); PopulateTotal( $("#audit_guest_id").html() ); $("#audit-trail-wrapper").removeClass("hide"); } else { $("#guest_name").html(""); $("#search").removeClass("hide"); $("#guest_id").html(""); $("#guest_id_wrapper").addClass("hide"); $("#search_guest_input").removeClass("guest-selected"); $("#search_guest_input").val(""); $("#search_guest_results").html(""); $("#search_guest_results").addClass("hide"); $("#activate-guest").addClass("mdl-button--disabled"); $("#audit-trail-wrapper").addClass("hide"); } event.stopPropagation(); }); $("#reconciliation_search_guest_results").on("click", ".guest" , function ( event ) { if ( $(event.target).closest(".guest").data("guestid") != undefined ) { $("#reconciliation_guest_name").html( $(event.target).closest('.guest').html()); $("#reconciliation_guest_id").html( $(event.target).closest('.guest').data("guestid")); $("#reconciliation-selection-wrapper").removeClass("hide"); $("#reconciliation_search_guest_input").val(""); $("#reconciliation_search_guest_results").html(""); $("#reconciliation_search_guest_results").addClass("hide"); PopulateTotal( $("#reconciliation_guest_id").html() ); } else { $("#reconciliation_guest_name").html(""); $("#reconciliation_guest_id").html(""); $("#reconciliation-selection-wrapper").addClass("hide"); $("#reconciliation_search_guest_input").removeClass("guest-selected"); $("#reconciliation_search_guest_input").val(""); $("#reconciliation_search_guest_results").html(""); $("#reconciliation_search_guest_results").addClass("hide"); } event.stopPropagation(); }); function FetchAuditTrail ( guestId ) { var url = "https://api.epic.foundation/gala/guest/audit"; $.ajax({ url: url, dataType: "json", method: "GET", data: { guestId : guestId, access_token: GetToken() }, cache: false, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("The Audit Trail could not be retrieved.", "La rapport d'activité n'a pu être retrouvé.", ERROR ); } }, success: function(data, status, request ) { if ( data && (Object.keys(data).length > 0 ) && (typeof data != "undefined" ) && (typeof data.event != "undefined" ) && (Object.keys(data.event).length > 0 )) { $("#itemized-tab").html(""); $.each( data.event , function ( index , element) { $("#audit_trail__body").append("\ \ " + element.event.timestamp + "\ \ " + element.event.qualifier1 + "\ " + element.event.qualifier2 + "\ " + element.event.qualifier3 + "\ "); }); } } }); } $("#activate-guest").click( function() { ActivateGuest( $("#guest_id").html() ); $("#activate-guest").addClass("mdl-button--disabled"); }); function ActivateGuest( guestid ) { var url = "https://api.epic.foundation/gala/guest/activate"; window.ajaxObj = $.ajax({ url: url, dataType: "json", method: "POST", cache: false, data: { access_token: GetToken(), guestId: guestid, pin : md5(guestid), gala : window.gala_id }, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { if ( (typeof object.responseJSON != "undefined") && ( typeof object.responseJSON.error != "undefined" ) ) { ShowMessage( object.responseJSON.error , "Une erreur a été détectée: " + object.responseJSON.error , ERROR ); } else { ShowMessage( "An error occurred: guest could not be checked in" , "Une erreur a été détectée: checkin annulé" , ERROR ); } } }, success: function(data, status, request) { HandleCheckinDataSuccess( data); } }); } function HandleCheckinDataSuccess ( data ) { if ( typeof data != "undefined" && typeof data.status != "undefined" && data.status == "OK") { ShowMessage("Activation confirmed.", "Activation confirmée", OK ); } else if ( typeof data != "undefined" && typeof data.error != "undefined" ) { ShowMessage("An error occurred " + data.error , "Une erreur d'interprétation a été détectée : " + data, ERROR ); } else { ShowMessage("An connectivity error occurred. The activation failed.", "Une erreur de connexion a été détectée. L'activation a échoué.", ERROR ); } } $(".add-guest").click( function ( event ) { $("#audit_search_guest_results").html(""); $("#addguest").removeClass("hide"); $("#add-firstname").focus(); $("#add-firstname").select(); event.stopPropagation(); }); $("#beginNextCheckin").click( function ( event ) { $("#search_guest_results").html(""); $("#search_guest_results").addClass("hide"); $("#guest_name").html(""); $("#guest_id").html(""); $("#guest_id_wrapper").addClass("hide"); $("#search_guest_input").val(""); $("#addguest input").val(""); $("#addguest .mdl-textfield").removeClass("is-dirty"); $("#search_guest_input").focus(); $("#search_guest_input").select(); $("#activate-guest").addClass("mdl-button--disabled"); $("#search").removeClass("hide"); event.stopPropagation(); }); // Add guest when not present $("#add-submit").click( function ( event ) { if ($("#add-firstname").val() == "") { $("#add-firstname").addClass("missing"); return; } if ($("#add-lastname").val() == "") { $("#add-lastname").addClass("missing"); return; } if ($("#add-email").val() == "") { $("#add-email").addClass("missing"); return; } var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; if (!re.test( $("#add-email").val())) { $("#add-email").addClass("missing"); return; } var url = "https://api.epic.foundation/gala/guest"; window.ajaxObj = $.ajax({ url: url, dataType: "json", method: "POST", cache: false, data: { access_token: GetToken(), title: $("#add-title").val(), first: $("#add-firstname").val(), last: $("#add-lastname").val(), email: $("#add-email").val(), guestId: $("#add-id").val() }, error: function(object, status, error ) { if ( object.statusText != 'abort' ) { ShowMessage("An error occurred. The guest was not added.", "Une erreur a été détectée. L'invité n'a pu être ajouté", ERROR ); } }, success: function(data, status, request) { ShowMessage("Guest added.", "Invité ajouté", OK ); $("#addguest").addClass("hide"); $("#search_guest_input").data( "guestid" , data[0].guest.guestId); $("#guest_name").html( data[0].guest.first + " " + data[0].guest.last ); $("#guest_id").html( data[0].guest.guestId ); $("#guest_id_wrapper").removeClass("hide"); $("#search").addClass("hide"); $("#search_guest_input").val(""); $("#search_guest_results").html(""); $("#search_guest_results").addClass("hide"); $("#activate-guest").removeClass("mdl-button--disabled"); } }); event.stopPropagation(); }); // A click on the language chooser updates the page and the session $("#language_selector_wrapper button").click( function( event ){ epic_UpdateLanguage ( $(event.target).closest(".language_selector").data("lang") , true ); $("#splash,#language-centralizer").addClass("hide"); $("#splash").removeClass("is-active"); $("#login").removeClass("hide"); $("#login").addClass("is-active"); event.stopPropagation(); }); // org tab function getOrganizations () { //get the list of organizations $.ajax({ url: "https://api.epic.foundation/portfolio/organization", dataType: "json", method: "GET", data: { access_token: GetToken() }, cache: false, success: function( portfolioData, status, request ) { if ( ( typeof portfolioData != "undefined") && ( typeof portfolioData.organizations != "undefined") ) { $.each( portfolioData.organizations , BuildOrganization ); } } }); } // Builds the organization block function BuildOrganization ( index , organizationJsonElement ) { var id = organizationJsonElement.organization.id; var org = $("
"); org.append("
" + organizationJsonElement.organization.name + "
"); org.append(""); org.append("
"); org.append("
"); // org.append("

" + organizationJsonElement.organization.name + "

"); org.append("
"); $("#" + id + " .sectors").append( "" + organizationJsonElement.organization.since + "" ); $("#portfolio-organizations").append( org ); // enrich with the sectors $.ajax({ url: "https://api.epic.foundation/portfolio/organization/" + id + "/sector", dataType: "json", method: "GET", id: id, data: { access_token: GetToken() }, cache: false, success: function( sectorsJsonElement , status, request ) { if ( (typeof sectorsJsonElement != "undefined") && (typeof sectorsJsonElement.sectors != "undefined") && (Object.keys(sectorsJsonElement.sectors).length > 0) ) { $.each( sectorsJsonElement.sectors , AddOrganizationSectorsClosureFn( this.id )); } } }); // enrich with introduction $.ajax({ url: "https://api.epic.foundation/portfolio/organization/summary", dataType: "json", method: "GET", id: id, data: { access_token: GetToken(), id: id, lang: $("#get-portfolio-organization-summary-language-filter").val() }, cache: false, success: function( summaryJsonElement , status, request) { if ( (typeof summaryJsonElement != "undefined") && (typeof summaryJsonElement.summaries != "undefined") && (Object.keys(summaryJsonElement.summaries).length > 0) ) { $.each( summaryJsonElement.summaries , AddSummaryClosureFn( this.id )); } } }); // enrich with description $("#" + id + " .data").append("
\ Lire\ More\
"); $.ajax({ url: "https://api.epic.foundation/portfolio/organization/introduction", dataType: "json", method: "GET", id: id, data: { access_token: GetToken(), id: id }, cache: false, success: function( introductionJsonElement , status, request) { if ( (typeof introductionJsonElement != "undefined") && (typeof introductionJsonElement.introductions != "undefined") && (Object.keys(introductionJsonElement.introductions).length > 0) ) { $.each( introductionJsonElement.introductions , function ( index , element ) { $("#" + element.introduction.id + "_MORE_TEXT" ).append("" + element.introduction.text + ""); }); } epic_UpdateLanguage( $("html").attr("lang") , false ); } }); } $("#portfolio-organizations").on("click", ".read-more-button", function ( event ) { $("#" + $(this).closest(".read-more-button").data("org") + "_MORE_TEXT" ).removeClass("hide"); $("#" + $(this).closest(".read-more-button").addClass("hide")); }); function AddSummaryClosureFn( id ) { var orgId = id; return function ( index , element ) { //add the list of sectors to organization $.each( element.sector , BuildSummaryBlockClosureFn ( element.summary , orgId )); } } function BuildSummaryBlockClosureFn (summary , orgId ) { var id = orgId; var summaryDOM = "" + summary.text + ""; summaryDOM = summaryDOM.replace( summary.highlight , "" + summary.highlight + "" ); // Add the sector to the DOM $("#" + id + " .summary" ).append( summaryDOM ); epic_UpdateLanguage( $("html").attr("lang") , false ); } // returns an iterating function to build the sectors for the org block // with the org id present in the scope for subsequent insertion into // the proper DOM element function AddOrganizationSectorsClosureFn( id ) { var orgId = id; return function ( index , element ) { //add the list of sectors to organization $.each( element.sector , BuildSectorBlockClosureFn ( element.sector , orgId )); } } // returns an iterating function to get the labels for the sectors // with the org id and the sector element in context function BuildSectorBlockClosureFn (sector , orgId ) { var id = orgId; var sectorElement = sector; var sectorIdDOM = id + "_" + sectorElement.sectorId; var sectorDOM = $(""); // Add the sector to the DOM $("#" + id + " .sectors" ).append( sectorDOM ); // add the labels if ( Object.keys(sectorElement.labels).length > 0) { $.each( sectorElement.labels , AddSectorLabelClosureFn( sectorElement , id , sectorIdDOM )); } return function ( index , element ) { //add a label for reach language //$.each( sector.labels , AddSectorLabelClosureFn( sectorElement , id , sectorIdDOM )); } } // returns an iterative function to loop throuh all the sector lang labels // with the org ID and the sector element in context for subsequent insertion // into the DOM function AddSectorLabelClosureFn ( sectorElement , orgId , sectorIdDOM ) { var sector = sectorElement ; var id = orgId; var domTarget = sectorIdDOM; return function ( index , element ) { //add a label for reach language $("#" + domTarget ).append("" + element.label.sectorName + ""); epic_UpdateLanguage( $("html").attr("lang") , false ); } } });