!function(a){Drupal.behaviors.clickable={attach:function(c){a('[data-clickable!=""][data-clickable]',c).once("clickable").addClass("block--linked").on("click",(function(){window.location.hash&&history.replaceState("","",a(this).data("clickable")),window.location.href=a(this).data("clickable")}))}}}(jQuery); ; Drupal.cl=Drupal.cl||{},function(n){n.extend(Drupal.cl,{color:{shade:function(n,r){return n.length>7?function(n,r){var t=n.split(","),a=r<0?0:255,e=r<0?-1*r:r,u=parseInt(t[0].slice(4)),s=parseInt(t[1]),o=parseInt(t[2]);return"rgb("+(Math.round((a-u)*e)+u)+","+(Math.round((a-s)*e)+s)+","+(Math.round((a-o)*e)+o)+")"}(n,r):function(n,r){var t=parseInt(n.slice(1),16),a=r<0?0:255,e=r<0?-1*r:r,u=t>>16,s=t>>8&255,o=255&t;return"#"+(16777216+65536*(Math.round((a-u)*e)+u)+256*(Math.round((a-s)*e)+s)+(Math.round((a-o)*e)+o)).toString(16).slice(1)}(n,r)},blend:function(n,r,t){return n.length>7?(a=r,e=t,u=n.split(","),s=a.split(","),o=parseInt(u[0].slice(4)),l=parseInt(u[1]),i=parseInt(u[2]),"rgb("+(Math.round((parseInt(s[0].slice(4))-o)*e)+o)+","+(Math.round((parseInt(s[1])-l)*e)+l)+","+(Math.round((parseInt(s[2])-i)*e)+i)+")"):function(n,r,t){var a=parseInt(n.slice(1),16),e=parseInt(r.slice(1),16),u=a>>16,s=a>>8&255,o=255&a,l=e>>16,i=e>>8&255,c=255&e;return"#"+(16777216+65536*(Math.round((l-u)*t)+u)+256*(Math.round((i-s)*t)+s)+(Math.round((c-o)*t)+o)).toString(16).slice(1)}(n,r,t);var a,e,u,s,o,l,i}}})}(jQuery); ; Drupal.cl=Drupal.cl||{};var site=site||{};site.util=site.util||{};var console=console||{log:function(){return!1}};!function(t){Drupal.behaviors.clClientToggle={attach:function(t,e){site.client&&site.client.controls&&site.client.controls()}},Drupal.behaviors.mpLanguageToggle={attach:function(e,i){"undefined"!=typeof mp_language_id&&t('input[name="LANGUAGE_ID"]').val(mp_language_id)}},Drupal.behaviors.backToTopToggle={attach:function(e,i){t(window).on("scroll",_.throttle((function(){t(this).scrollTop()>220?t(".back-to-top").fadeIn(500):t(".back-to-top").fadeOut(500)}),100)),t(".back-to-top").on("click",(function(e){return e.preventDefault(),t("html, body").animate({scrollTop:0},500),!1}));var r={};t("a").each((function(){var e=t(this).attr("name");e&&(r[e]=1)})),t('a[href^="#"]').each((function(e){var i=t(this).attr("href");i=i.substring(1),r[i]&&t('a[name^="'+i+'"]').addClass("anchorOffset")}))}},t.extend(Drupal.cl,{hasPersonalization:function(){var t=Drupal||{};return t=(t=t.settings||{}).cl||{},personalization=t.personalization||0,1===personalization},isNumeric:function(t){return("number"==typeof t||"string"==typeof t)&&""!==t&&!isNaN(t)},tryGetObject:function(t,e,i){var r=[];for(var o in t)t.hasOwnProperty(o)&&("object"==typeof t[o]?r=r.concat(Drupal.cl.tryGetObject(t[o],e,i)):o==e&&t[e]==i&&r.push(t));return r},implode:function(t,e){var i="",r="",o="";if(1===arguments.length&&(e=t,t=""),"object"==typeof e){if("[object Array]"===Object.prototype.toString.call(e))return e.join(t);for(i in e)r+=o+e[i],o=t;return r}return e},getTopHeight:function(){var t=this.getElements().top.outerHeight(!0);return this.isNumeric(t)?t:0},getToolbarHeight:function(){var t=this.getElements().toolbar.outerHeight(!0);return this.isNumeric(t)?t:0},getElements:function(){return void 0===this.getElements.elements&&(this.getElements.elements={body:t("body"),toolbar:t("#toolbar"),top:t("#top"),nav:t("#navigation"),main:t("#main"),footer:t("#footer")}),this.getElements.elements},responsiveColumns:function(e){var i=e.length;if(i>0){var r=Math.floor(100/i);e.each((function(){t(this).css("width",r+"%")}));var o=0;t(window).resize((function(){e.each((function(){t(this).css("height","auto");var e=t(this).height();e!==o&&(o=e)})).css("height",o+"px")})).resize()}},template:{js:function(e){return t("script.inline-template[path='"+(e=void 0!==e?e:"foobar_template")+"']").html()},get:function(t){var e=t.path,i=t.object,r=t.callback,o=t.partials;if("string"==typeof e&&!(e.length<1)){for(key in data=void 0!==i?i:{},o=void 0!==o?o:{})o.hasOwnProperty(key)&&(o[key]=this.js(o[key]));var n=this.js(e),a=Mustache.render(n,data,o);if("function"==typeof r){var s=r(a,data);if(void 0!==s)return s}}}},getQSParams:function(){for(var t,e=[],i=window.location.href.slice(window.location.href.indexOf("?")+1).split("&"),r=0;r,.\/? ])+/g,"-").replace(/^(-)+|(-)+$/g,"")},hasQueryString:function(t){return!_.isEmpty(t.split("?")[1])}}),Drupal.behaviors.ctaButton={cl:Drupal.cl,actionCbs:{},isEmpty:function(t){return!t||!/[^\s]+/.test(t)},isObject:function(t){return"[object Array]"!==Object.prototype.toString.call(t)&&(null!==t&&"object"==typeof t)},hasProps:function(t){if(0==this.isObject(t))return!1;var e=0;for(var i in t)t.hasOwnProperty(i)&&e++;return e>0},getActionClass:function(t){for(var e=t.length,i=this.isActionClass,r=e-1;r>=0;r-=1)if(i(t[r]))return t[r];return!1},isActionClass:function(t){return"action-"==t.substring(0,7)},actions:{getSkuId:function(t){var e=t.attr("data-productid"),i=t.attr("data-skubaseid"),r=t.attr("page-data-key");if(void 0===i){var o=page_data[r].products.filter((function(t){return t.PRODUCT_ID===e}))[0];void 0!==o&&(i=o.skus[0].SKU_BASE_ID)}else i=-1==i.indexOf("SKU")?i:i.replace("SKU","");return i},quickview:function(e,i){if(void 0!==site&&void 0!==site.quickshop&&void 0!==site.quickshop.render){e.preventDefault(),console.log("JGA - revisit Drupal.behaviors.ctaButton.actions.quickview to get product data");var r=t(),o=i.attr("data-productid"),n=i.attr("page-data-key"),a=page_data[n].products.filter((function(t){return t.PRODUCT_ID===o}))[0],s=i.closest(".js-product");s.length&&a&&(a.priceRange=s.data("formattedPrice")||a.priceRange,a.skus?a.skus=a.skus.filter((function(t){return s.data("formattedPrice")&&a.GIFTSET_COMPONENTS&&t.PRODUCT_ID===o&&(t.formattedPrice=s.data("formattedPrice")),t.PRODUCT_ID===o})):a.skus=page_data["product-input-type"].skus.filter((function(t){return s.data("formattedPrice")&&a.GIFTSET_COMPONENTS&&t.PRODUCT_ID===o&&(t.formattedPrice=s.data("formattedPrice")),t.PRODUCT_ID===o})));var c=site.quickshop.render({productData:a});if(c.css("display","block").find(".close").hide(),"object"==typeof c)generic.overlay.launch({content:c,includeBackground:!0,hideOnClickOutside:!0,includeCloseLink:!0,cssStyle:{}}),(r=c.filter(".js-quickshop")).find("[data-sells-with]").length&&t(document).trigger("sells_with_init",r);return!1}},add_to_bag:function(t,e){if(void 0!==site&&void 0!==site.addToCart){if(!e.is("[data-productid]"))return;t.preventDefault();var i=this.getSkuId(e);return e.hasClass("add-both-to-bag")||site.addToCart({skuBaseId:i}),!1}},add_to_favorites:function(t,e){if(void 0!==site&&void 0!==site.addToFavorites){if(!e.is("[data-productid]"))return;t.preventDefault();var i=this.getSkuId(e);return site.addToFavorites({skuBaseId:i}),!1}}},initCTAButton:function(e){var i=this,r=e,o=r.css("background-color"),n=/background\-color\:/.test(r.attr("style")),a=r.attr("bg-hover"),s=r.css("color"),c=/(?:\-)color\:/.test(r.attr("style")),u=r.attr("text-hover"),l=r.attr("class").split(/\s+/),d=i.getActionClass(l);0!=d&&((d=d.replace("action-","").replace(/\-/g,"_"))in i.actionCbs||(i.actionCbs[d]=t.isFunction(i.actions[d])),1==i.actionCbs[d]&&r.on("click",(function(e){i.actions[d](e,t(this))}))),r.hover((function(){t(this).addClass("hover");var e={};0==i.isEmpty(a)&&(e["background-color"]=a),0==i.isEmpty(u)&&(e.color=u),i.hasProps(e)&&t(this).css(e)}),(function(){t(this).removeClass("hover");var e={};n&&(e["background-color"]=o),c&&(e.color=s),i.hasProps(e)&&t(this).css(e)}))},init:function(e){e=void 0!==e?e:document;var i=this;t(".button.cta",e).not(".add-both-to-bag").not(".button_both").once("cta-btn").each((function(){i.initCTAButton(t(this))}))},attach:function(t,e){this.init()}},Drupal.behaviors.socialShare={attach:function(e,i){var r={"%SHARE_LINK%":encodeURIComponent(window.location.origin+window.location.pathname+"#12345")};t(".social-share").find(".share-button").each((function(){var e=t(this),i=t(this).attr("href");i=i.replace(/%\w+%/g,(function(t){return r[t]||t})),e.attr({href:i,target:"_blank"})}))}},t.fn.lazybind=function(e,i,r,o){var n=null;t(this).on(e,(function(t){var e=t;n=setTimeout((function(){i(e)}),r)})),null!=o&&t(this).on(o,(function(){null!=n&&clearTimeout(n)}))},Array.prototype.indexOf||(Array.prototype.indexOf=function(t){var e=this.length>>>0,i=Number(arguments[1])||0;for((i=i<0?Math.ceil(i):Math.floor(i))<0&&(i+=e);i"),s=$productImg.width(),c=$productImg.height(),u=c/4;a.css({"background-color":o,"border-radius":"50%",height:c,width:s}),$productImg.wrap(a),$productImg.css({float:"right","margin-top":u})}))}},site.util.refreshSelectBoxes=function(e){e.each((function(){var e=t(this).data("selectBox-control");e&&e.length&&t(this).selectBox("refresh")}))},site.util.lazyLoaded=function(e,i){i=i||"scroll",e.find("img").each((function(e){t(this).hasClass("lazy")&&t(this).removeAttr("src").hide()}));var r="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";e.find("img.lazy").show().lazyload({effect:"fadeIn",event:i,failure_limit:100,threshold:200,placeholder:r}),e.find("div.lazy").lazyload({failure_limit:100,threshold:200,placeholder:r})},Drupal.behaviors.prodcatUiInit={attach:function(e){t(".js-product",e).trigger("product.init")}}}(jQuery); ; var site=site||{};site.favorites=site.favorites||{},jQuery,site.favorites.manipulateWishList=function(a){var t,s={_SUBMIT:"alter_collection",action:"add"};if((a=a||{}).skuData&&a.skuData.SKU_BASE_ID?t=a.skuData.SKU_BASE_ID:a.skuBaseId&&(t=a.skuBaseId),t&&(s.SKU_BASE_ID=t),s.action=a.action||s.action,a.COLLECTION_ID&&(s.COLLECTION_ID=a.COLLECTION_ID),a.skuData&&a.skuData.PARENT_CAT_ID){var o=a.skuData.PARENT_CAT_ID.match("[0-9]+");o&&(s.CAT_BASE_ID=o[0])}var e=a.successCallback||function(){},r=a.errorCallback||function(){};generic.jsonrpc.fetch({method:"rpc.form",params:[s],onSuccess:function(a){console.log("modify favorites success"),console.log(a.getData());var t=a.getData().ac_results[0].result;e(t)},onFailure:function(a){console.log("modify favorites failure"),console.log(a.getError()),r(a.getError())}})}; ; var site=site||{};site.geo=site.geo||{},site.geo.locate=function(o,t){if(window.blackberry&&blackberry.location.GPSSupported){if(void 0===blackberry.location.setAidMode)return void t();blackberry.location.setAidMode(2);!function(o,t,e){var i;i=setTimeout((function(){clearTimeout(i),t()}),1e3);blackberry.location.onLocationUpdate((function(){var e=blackberry.location.latitude,i=blackberry.location.longitude;if(e||i){var a={};a.coords={latitude:e,longitude:i},o(a)}else t()})),blackberry.location.refreshLocation()}(o,t)}else navigator.geolocation.getCurrentPosition((function(t){var e,i;e=t.coords.latitude,i=t.coords.longitude,site.geo.hasCurrentLocation=!0,site.geo.currentLocationData={latitude:e,longitude:i},o&&o({lat:e,lng:i})}),(function(){t&&t()}))}; ; var site=site||{};!function(e){var t=[];site.loading={show:function(a){var s,i={class:"loading-status",css:{}},r=e(a.target),g=e("",{src:"/media/export/cms/479-01 Clinique_LoadingGif_R22.gif",css:{height:"100%"}});if(a.matchTarget&&a.matchTarget.length>0)for(var n=0;n",i).append(g),r.hide().before(s),t.push({target:r,loading:s}),t.length-1},hide:function(e){null==e&&(e=t.length-1),void 0!==t[e]&&(t[e].loading.remove(),t[e].target.show(),delete t[e])}}}(jQuery); ; var site=site||{};site.locator=site.locator||{},site.locator.geocodeResultFilter=function(t,i,e){var o,s,a,n=jQuery.extend([],t);for(i=i||["country","route"],e=e||["point_of_interest","premise","subpremise"],o=0;o-1&&n.length){if(c=(r=a(":tabbable")).index(n),u&&("text"===p||"email"===p||"password"===p)&&(n.val().trim().length>0||" "===i))return;switch(i){case"ArrowLeft":case"ArrowUp":t(0===c?-1:c-1);break;case"ArrowRight":case"ArrowDown":c===r.length-1?t(0):t(c+1);break;case"Enter":case" ":e&&clearTimeout(e),(!n.is("a")&&!n.is("button")&&!n.is(":checkbox")||" "===i&&n.is("a"))&&n[0].click(),n.hasClass("close-popup")&&o(c-1),n[0].hasAttribute("aria-haspopup")&&o(c+1);break;case"Escape":n.hasClass("close-popup")&&(n.trigger("click"),t(c-1))}}}))}}}(jQuery,Drupal); ; var tms_page_data=tms_page_data||{},generic=generic||{},site=site||{};site.userInfoCookie=site.userInfoCookie||{},site.onLoadRpc=site.onLoadRpc||{},site.onLoadRpc.requests=site.onLoadRpc.requests||[],site.onLoadRpc.hasFetched=!1,site.legacy_user_site=!0,function(e){site.onLoadRpc.init=function(){var t=[];e("[data-productid]").each((function(){for(var s=e(this).attr("data-productid"),a=!0,r=t.length-1;r>-1;r--)if(t[r]===s){a=!1;break}a&&t.push(s),a=!0})),t.length&&site.onLoadRpc.requests.push({method:"prodcat",params:[{products:t,category_fields:["products"],product_fields:["PRODUCT_ID","PROD_RGN_NAME","PROD_RGN_SUBHEADING","SHORT_DESC","skus","GIFTSET_COMPONENTS"],sku_fields:["SKU_ID","INVENTORY_STATUS","DISPLAY_STATUS","SKU_BASE_ID","RELEASE_DATE","PRODUCT_ID","isOrderable","isShoppable","isPreOrder","PRODUCT_SIZE","LIFE_OF_PRODUCT","formattedUnitPrice","formattedPrice","PRICE","IMAGE_5UP","LARGE_IMAGE","DISCOUNTABLE","isDiscountable","PRODUCT_CODE"]}],onSuccess:function(t){e(document).trigger("prodcat.status",t)}}),1===parseInt(site.userInfoCookie.getValue("signed_in"))||1===parseInt(site.userInfoCookie.getValue("csr_logged_in"))?site.onLoadRpc.requests.push({method:"user.fullData",params:[{}],onSuccess:function(t){if(void 0===t||void 0===t.result||null==t.result.value)return null;var s=t.result.value;void 0!==s.csr_email&&null!==s.csr_email&&e("#csr_header_holder").removeClass("hidden"),e("body").addClass(1===s.signed_in?"elc-user-state-logged-in":"elc-user-state-anonymous"),e('[data-pg-object="user"] > [data-pg-prop], [data-pg-object="user"][data-pg-prop]').each((function(){var t=e(this);t.html(s[t.attr("data-pg-prop").toLowerCase()])})),generic.user.setUser(s),e(document).trigger("user.loaded",s)},onFailure:function(){}}):(generic.user.setUser({}),e("body").addClass("elc-user-state-anonymous"),e(document).trigger("user.loaded",{}))},site.onLoadRpc.fetch=function(){var t=site.onLoadRpc.requests||[],s=t.length,a=[];site.onLoadRpc.hasFetched=!0;for(var r=0,o=s;r0&&generic.jsonrpc.fetch({method:"trans.get",params:[{trans_fields:["TRANS_ID","totals"],payment_fields:[],order_fields:["items","samples","offerCodes"]}],onSuccess:function(t){var a=t.getValue();if(void 0!==a&&null!=a)return $(document).trigger("cart.loaded",a),$('[data-pg-object="cart"] > [data-pg-prop], [data-pg-object="cart"][data-pg-prop]').each((function(t,r){a.hasOwnProperty($(r).attr("data-pg-prop"))&&$(r).html(a[$(r).attr("data-pg-prop")])})),site.userTransObj.trans_obj=a,site.userTransObj.trans_obj},onFailure:function(t){var a=t.getValue();if(null!=a)return $(document).trigger("cart.loaded",a),$('[data-pg-object="cart"] > [data-pg-prop], [data-pg-object="cart"][data-pg-prop]').length>0&&$('[data-pg-object="cart"] > [data-pg-prop], [data-pg-object="cart"][data-pg-prop]').each((function(t){var r=$(t).attr("data-pg-prop");Object.prototype.hasOwnProperty.call(a,r)&&$(t).html(a[r])})),site.userTransObj.trans_obj=a,site.userTransObj.trans_obj}})},site.userTransObj.setTransObject=function(t){site.userTransObj.trans_obj=t}; ; !function(t){Drupal.behaviors.toolbarAdjustments={doAdjustments:function(){var t=Drupal.cl.getElements();if(t.body.hasClass("toolbar")&&"fixed"==t.top.css("position")&&"-115px"!=t.top.css("top")){var n=Drupal.cl.getToolbarHeight();n>0&&t.top.css({top:n+"px"})}},init:function(){var n=this;n.doAdjustments(),t(window).resize((function(){n.doAdjustments()}))},attach:function(t,n){this.init()}},Drupal.behaviors.fixedHeaderAdjustments={doAdjustments:function(){var t=Drupal.cl.getElements(),n={};if("fixed"==t.top.css("position")){var e=Drupal.cl.getTopHeight();n["padding-top"]=e+"px"}var o=0;for(prop in n)n.hasOwnProperty(prop)&&o++;o>0&&t.main.css(n)},init:function(){var n=this;n.doAdjustments(),t(window).resize((function(){n.doAdjustments()}))}},Drupal.behaviors.capsChecker={doAdjustments:function(){var n=t(".form-text");n.each((function(){var n=t(this).css("height"),e=t(this).width(),o=t(this).attr("name"),a=t('').css({cursor:"pointer",display:"none",height:n,"line-height":n,"margin-left":e+"px","pointer-events":"none",position:"absolute"});t(this).before(a)})),n.capsChecker({capson:function(n,e){t(this).siblings(".caps-warning").show()},capsoff:function(n,e){t(this).siblings(".caps-warning").hide()}})},init:function(){this.doAdjustments()},attach:function(t,n){this.init()}},Drupal.behaviors.placeholderPolyfill={attach:function(n,e){t(document).ready((function(){t("input[placeholder], textarea[placeholder]").placeholder()}))}},Drupal.behaviors.bigText={attach:function(n,e){t(document).ready((function(){t(".textfill").each((function(){t(this).textfill({maxFontPixels:36})}))}))}},Drupal.behaviors.isIpad=null!=navigator.userAgent.match(/iPad/i),Drupal.behaviors.launchBlueOcean={getPath:function(){return"/blue_ocean/quiz_overlay.tmpl"},launchBlueOcean:function(n){var e="780px",o="ob_overlay";Drupal.behaviors.isIpad&&t("html").width()<962&&(e="760px",o="ob_overlay ipad_ob_overlay"),generic.template.get({path:n,forceReload:!0,callback:function(n){generic.overlay.launch({content:n,cssStyle:{width:e,height:"525px"},cssClass:o});var a=t(window).height();if(525-a>0){var i=(525-a)/2+5+"px";t(".ob_overlay .close-container").css("top",i)}}})},attach:function(n,e){var o=this;t(".blueOceanQuizButton",n).once("bo-button-overlay").on("click",(function(n){if(!Drupal.settings.globals_variables.gdpr_compliant||!t(n.target).hasClass("tools-pages")){var e=t(this).attr("href");return void 0!==e&&""!=e||(e=o.getPath()),o.launchBlueOcean(e),!1}n.preventDefault()}))}},Drupal.behaviors.launchFoundationFinder={getPath:function(){return"/foundation_finder/frame.tmpl"},launchFoundationFinder:function(t){generic.template.get({path:t,forceReload:!0,callback:function(t){generic.overlay.launch({content:t,cssStyle:{width:"auto",height:"auto"},cssClass:"ff_overlay"})}})},attach:function(n,e){var o=this,a=this.getPath();t(".foundationFinderQuizButton",n).once("ff-button-overlay").on("click",(function(n){if(!Drupal.settings.globals_variables.gdpr_compliant||!t(n.target).hasClass("tools-pages"))return o.launchFoundationFinder(a),!1;n.preventDefault()}))}},window.console||(window.console={log:function(){}}),Drupal.behaviors.footerAdjustments={hasRun:!1,init:function(){function n(){var n=t(window),e=Drupal.cl.getElements().footer,o=n.height(),a=document.querySelector("body#signin #content .social-login")?225:65;o<=t("#top_wrapper").outerHeight(!0)+t("#wrapper, #main").outerHeight(!0)+a?e.addClass("bottom-auto"):e.removeClass("bottom-auto")}var e=_.throttle(n,200);n(),t(window).resize(e)},attach:function(t,n){this.hasRun||(this.init(),this.hasRun=!0)}},Drupal.behaviors.msgOverlays={attach:function(n,e){t(document).on("addToCart.success",(function(n,e){var o=e.ac_results&&e.ac_results.length?e.ac_results[0].result.OVERLAY:void 0;void 0!==o&&setTimeout((function(){generic.overlay.launch({content:o,includeBackground:!0,cssClass:"offer-overlay"}),t(".overlay-container").on("click",(function(){generic.overlay.hide()}))}),500)}))}}}(jQuery); ; !function(e){e(document).ready((function(){if(-1!==window.location.href.indexOf("#blue_ocean")){var n=window.location.href,l=-1!==n.indexOf("#blue_ocean_women")?"/lcl/blue_ocean/quiz/welcome.html?womensQuiz":-1!==n.indexOf("#blue_ocean_men")?"/lcl/blue_ocean/quiz/welcome.html?mensQuiz":"/lcl/blue_ocean/quiz/welcome.html",o=-1!==n.indexOf("#blue_ocean_men")?"close-link-white":"",i=e('');generic.overlay.launch({content:i,cssStyle:{padding:"0px",height:"511px",overflow:"hidden",border:"none"},cssClass:o,includeBackground:!0})}}))}(jQuery); ; !function(n){n(document).ready((function(){if(-1!==window.location.href.indexOf("#foundation_finder")){var i=window.location.href,o=i.indexOf(!0)?"/foundation_finder/option.tmpl":"/foundation_finder/option.tmpl?reset_date=1",e=i.indexOf(!0)?"close-link":"",r=n('');generic.overlay.launch({content:r,cssStyle:{padding:"0px",height:"575px",overflow:"hidden",border:"none"},cssClass:e,includeBackground:!0})}}))}(jQuery); ; var generic=generic||{},site=site||{};generic.endeca=generic.endeca||{catalog:{},result:{},results:{},resultsgroup:{},mixins:{},instances:{},generic:{Class:generic.Class||{},env:generic.env||{},rb:generic.rb||{},template:generic.template||{}},helpers:{array:{toInt:function(e){for(var t=0;t1}));return function(){return e.apply(t,s)}}},string:{toQueryParams:function(e,t){t=t||"&";var s,i,n,r,a=(e=e||"").substring(e.indexOf("?")+1).split("#")[0].split(t||"&"),o={};for(s=0;s-1&&(e=e.split("?")[1]),s.forEach((function(e){var s=e.split("=");t[s[0]]=decodeURIComponent(s[1]||"")})),t}()||{}},query:function(e){return generic.endeca.generic.env.parsedQuery()[e]||null}},generic.endeca.generic.template=function(){var e,t={},s={},i=function(t){var i=t.template;if(i=n({template:i,recurseParams:{object:t.object,rb:t.rb},Lre:/\[jsInclude\]/i,Rre:/\[\/jsInclude\]/i}),"object"==typeof t.rb&&(i=n({template:i,obj:t.rb,Lre:/\[rb\]/,Rre:/\[\/rb\]/})),"object"==typeof t.object)try{if(i.match(/\{\{.*\[/)&&i.match(/\].*\}\}/))throw"generic.template: template expects array notation, defaulting to non-mustache rendering";e=e||{globals:{t:site.translations||{},variables:Drupal.settings.common||{}}};var r=$.extend({},t.object,e);i="function"==typeof Mustache.to_html?Mustache.to_html(i,r,s):Mustache.render(i,r,s)}catch(e){console.log(e),i=n({template:i,obj:t.object})}return i},n=function(e){(e=e||{}).Lre=e.Lre||/\{\{\{|\{\{/,e.Rre=e.Rre||/\}\}\}|\}\}/;var s,i=e.obj||e.rb||{},n=e.template||"",r=e.recurseParams||null,a=new RegExp(e.Lre),o=new RegExp(e.Rre);s=n.replace(/[\r\t\n]/g," ").split(a);for(var c="",u=0;u1){var C=f[0],v=f[1];if("."===m)d=i[C][v]&&"undefined"!==i[C][v]?i[C][v]:"";else{v=v.substring(1);var R=m.match(/\d+/g),y=null!==R?parseInt(R[0],10):0;d=i[C][y][v]&&"undefined"!==i[C][y][v]?i[C][y][v]:""}}}h=d.toString()+l[1]}c+=h}return c};return t.get=function(e){var t,n=e.path,r=(e.callback,!!e.forceReload),a=e.object,o=e.rb,c=function(e){var t=s[e];return!t&&site.templates&&site.templates[e]&&(s[e]=site.templates[e].content,t=s[e]),t}(n);if(c&&!r)t=i({template:c,object:a,rb:o,callback:e.callback});else{var u=null;jQuery(".inline-template").each((function(){jQuery(this).html()&&jQuery(this).attr("path")==n&&(u=this)})),u&&(c=function(e,t){return s[e]=t,t}(n,jQuery(u).html()),t=i({template:c,object:e.object,rb:o,callback:e.callback}))}if("function"!=typeof e.callback)return t;e.callback(t)},t.loadMustacheMappings=function(e){if((e=e||{mappings:{}}).mappings)for(var t in e.mappings)e.mappings.hasOwnProperty(t)&&site.templates[e.mappings[t]]&&(s[t]=site.templates[e.mappings[t]].content,s[e.mappings[t]]=site.templates[e.mappings[t]].content)},t}(),generic.endeca.catalog=site.endeca.generic.Class.create({initialize:function(e){this.jsonResult=null,this.resultList=[],jQuery.extend(this,e||{}),this.jsonResult&&this.parseData()},parseData:function(){if(this.jsonResult.AggrRecords)for(var e=0;e0&&(c.parseOrder=--this.parseOrderLo),(c=jQuery.extend(c,t)).skus||(c.skus=[]),c.skuList||(c.skuList={}),c.skuList[a]||c.skus.push(o),c.skuList[a]=o,this.productList[r]=c,o.product=c;var u=this.categoryList[n]||{};(u=jQuery.extend(u,e)).prods||(u.prods=[]),u.prods.push(c),this.categoryList[n]=u}},getProducts:function(){function e(e,t){return e.DISPLAY_ORDER>t.DISPLAY_ORDER?1:e.DISPLAY_ORDERt.parseOrder?1:e.parseOrder ");n&&(e="Search Results Filtered "+this.currentPage),this.contentCount>0&&0==this.productCount&&(s="*"+s),"function"==typeof cmCreatePageviewTag&&cmCreatePageviewTag(e,s,t,i.toString(),n),this.wildcardSearch?"function"==typeof cmCreateConversionEventTag&&cmCreateConversionEventTag("RESULTS PAGE",1,"ENDECA WILDCARD SEARCH",1):"function"==typeof cmCreateConversionEventTag&&cmCreateConversionEventTag("RESULTS PAGE",1,"NO ENDECA WILDCARD SEARCH",1)}},contentClick:function(){"function"==typeof cmCreatePageElementTag&&cmCreatePageElementTag("CONTENT","SEARCH DROPDOWN")},productClick:function(){"function"==typeof cmCreatePageElementTag&&cmCreatePageElementTag("PRODUCTS","SEARCH DROPDOWN"),this.wildcardSearch?"function"==typeof cmCreateConversionEventTag&&cmCreateConversionEventTag("SEARCH DROPDOWN",1,"ENDECA WILDCARD SEARCH",1):"function"==typeof cmCreateConversionEventTag&&cmCreateConversionEventTag("SEARCH DROPDOWN",1,"NO ENDECA WILDCARD SEARCH",1)},seeAllClick:function(){"function"==typeof cmCreatePageElementTag&&cmCreatePageElementTag("SEE ALL","SEARCH DROPDOWN")},reset:function(){this.refinementsList=[],this.pageView=!0}},site.endeca.coremetrics=generic.endeca.coremetrics;var tms_page_data=tms_page_data||{};site.endeca.omniture={enabled:!1,page_id:"Search Results",productCount:0,contentCount:0,searchTerm:null,searchType:"Regular",refinementsList:[],numberOfPages:1,currentPage:1,initialize:function(e){jQuery.extend(this,e)},searchResults:function(){var e=this.page_id+" "+this.currentPage,t=this.searchTerm,s=this.searchType;this.contentCount,this.productCount;this.contentCount>0&&0==this.productCount&&(t="*"+t),omnidata=[t,this.contentCount,this.productCount,e,s],void 0!==tms_page_data.tms_page_info?tms_page_data.tms_page_info.SEARCH=omnidata:tms_page_data.SEARCH=omnidata,jQuery(window).trigger("OMNISEARCH",[omnidata])},refineSearch:function(e){omnidata=[e,this.productCount],void 0!==tms_page_data.tms_page_info?tms_page_data.tms_page_info.FILTERSEARCH=omnidata:tms_page_data.FILTERSEARCH=omnidata,jQuery(window).trigger("FILTERSEARCH",[omnidata])},contentClick:function(){},productClick:function(){var e=this.page_id+" "+this.currentPage,t=this.searchTerm,s=this.searchType;this.contentCount,this.productCount;this.contentCount>0&&0==this.productCount&&(t="*"+t),omnidata=[t,this.contentCount,this.productCount,e,s],void 0!==tms_page_data.tms_page_info?tms_page_data.tms_page_info.TYPEAHEAD=omnidata:tms_page_data.TYPEAHEAD=omnidata,jQuery(window).trigger("OMNISEARCH",[omnidata]),$(document).trigger("SEARCHPRODUCTCLICK")},seeAllClick:function(){jQuery(window).trigger("SEARCHALLCLK")},reset:function(){this.refinementsList=[]}}; ; generic.endeca.meta=site.endeca.generic.Class.create({initialize:function(e){this.jsonResult=null,this.searchKey="all",this.hasRedirects=!1,this.redirecting=!1,this.pagination=null,this.sorting=[],this.dimensions={},this.metaInfo={},this.searchInfo={},this.supplementalObjects=[],this.supplementalContent={},jQuery.extend(this,e),this.jsonResult&&this.parseData()},parseData:function(e){this.processMetaInfo(),this.processSearchInfo(),this.processSupplemental(),this.processPagination(),this.processSorting(),this.processDimensions()},processMetaInfo:function(){this.metaInfo=this.jsonResult.MetaInfo||this.metaInfo,this.numberOfPages=this.getMetaProp("Number of Pages",1),this.recordsReturned=this.getMetaProp("Number of Records Returned",0),this.recordsPerPage=this.getMetaProp("Number of Records per Page",0),this.totalMatchRecords=this.getMetaProp("Total Number of Matching Records",0),this.totalAggrRecords=this.getMetaProp("Total Number of Matching Aggregate Records",0)},processSearchInfo:function(e){e=e||{totalContentRecords:0};var t=this.jsonResult&&this.jsonResult["Search Info"]&&this.jsonResult["Search Info"][this.searchKey]?this.jsonResult["Search Info"][this.searchKey]:{};if(this.searchInfo.searchTerm=t["Search Term"]||"",this.searchInfo.searchTerm.match(/\*$/)&&(this.searchInfo.searchTerm=this.searchInfo.searchTerm.slice(0,-1)),this.searchInfo.totalContentRecords=e.totalContentRecords||0,this.searchInfo.totalProductRecords=this.totalAggrRecords||this.totalMatchRecords,this.searchInfo.contentResultText=1==this.searchInfo.totalContentRecords?site.endeca.generic.rb("endeca").get("content_result"):site.endeca.generic.rb("endeca").get("content_results"),this.searchInfo.productResultText=1==this.searchInfo.totalProductRecords?site.endeca.generic.rb("endeca").get("product"):site.endeca.generic.rb("endeca").get("products"),this.searchInfo.totalRecords=parseInt(this.searchInfo.totalContentRecords)+parseInt(this.searchInfo.totalProductRecords),this.searchInfo.resultText=1==this.searchInfo.totalRecords?site.endeca.generic.rb("endeca").get("result"):site.endeca.generic.rb("endeca").get("results"),this.searchInfo.productText=1==this.searchInfo.totalRecords?site.endeca.generic.rb("endeca").get("product"):site.endeca.generic.rb("endeca").get("products"),this.searchInfo.startingRecord=this.searchInfo.totalProductRecords?this.getMetaProp("Starting Record Number",1):0,this.searchInfo.endingRecord=this.getMetaProp("Ending Record Number",1),this.searchInfo.originalRecords=this.searchInfo.totalRecords,this.searchInfo.originalResultText=this.searchInfo.resultText,this.searchInfo.originalProductText=this.searchInfo.productText,this.searchInfo.correctedTerms=[],t["Spell Correction"])for(var s=0;s1){var e=new site.endeca.query(jQuery.extend(!0,{},site.endeca.configuration.query,{recordsPerPage:1e4}));this.pagination={numberOfPages:this.numberOfPages,numberOfCurrentPage:this.getMetaProp("Page Number",1),viewAllLink:this.query.getMergedQueryString(e.toQueryString()),previousPageLink:this.getMetaProp("Previous Page Link"),nextPageLink:this.getMetaProp("Next Page Link"),directPageLinks:this.getMetaProp("Direct Page Links","")}}},processSorting:function(){var e=this.getMetaProp("Add Sort Key Links",[]),t=this.getMetaProp("Sorted By",[]);e.length&&(this.sorting=this.sorting.concat(e)),t.length&&(this.sorting=this.sorting.concat(t))},processDimensions:function(){var e=[],t=[];if(this.jsonResult.Breadcrumbs)for(var s=0;s]/)?t:""},configureLocale:function(e){e=e||{props:[],locale:""};for(var t=0;t0&&(this.resultNodes?.length??0)>=s)){var i=new this.resultClass({parent:this,templatePath:e.templatePath||this.templatePath,resultData:e.result,parentNode:e.contentNode||this.contentNode,configuration:t,mixins:e.mixins||this.mixins});this.resultNodes.push(i)}},setResultClass:function(e){var t=(e=e||{}).baseClass||this.baseClass||site.endeca.result;if(!this.resultClass){e.childClass=e.childClass||this.childClass||"";var s=e.mixins||this.mixins[this.resultMixinKey]||this.mixins["result."+e.childClass]||this.mixins.result||{};this.resultClass=e.childClass&&t[e.childClass]?site.endeca.generic.Class.create(site.endeca.generic.Class.mixin(t,s),t[e.childClass]):site.endeca.generic.Class.mixin(t,s)}},displayResultNodes:function(){for(var e=0;e1?t.parentNode.each((function(){e.parentNode=jQuery(this),t._super(e)})):t._super(e)},createResult:function(e){(e=e||{}).childClass=this.resultsChildClass||e.childClass,e.mixins=e.mixins||this.mixins[this.resultsMixinKey]||this.mixins["results."+e.childClass]||this.mixins.results,this.setResultClass(e);var t=new this.resultClass(jQuery.extend({parent:this,resultData:e.result,parentNode:this.contentNode||this.node||this.parentNode,summaryResultData:this.summaryResultData,mixins:this.mixins,configuration:e.configuration||this.configuration},e.resultsArgs||this.resultsArgs||{}));this.resultNodes.push(t)},reset:function(){for(var e=0;e1?site.endeca.generic.rb("language").get("reviews"):site.endeca.generic.rb("language").get("review"),this.resultData.ratingRounded=this.resultData.TOTAL_REVIEW_COUNT?Math.round(10*this.resultData.AVERAGE_RATING)/10:0},setupBrandData:function(){this.resultData.formattedPriceRange=this.formatPriceRange(),this.resultData.formattedCartridgePrice=void 0!==this.resultData.GIFTSET_COMPONENTS?this.resultData.skus[0].formattedCartridgePrice:"",this.resultData.price2=this.resultData.skus[0].formattedPrice2,this.resultData.shadedClass=this.resultData.shaded?"shaded":"nonshaded",this.resultData.sizedClass=this.resultData.sized?"sized":"notsized",this.resultData.isComingSoon=eval(jQuery.map(this.resultData.skus,(function(e){return e.isComingSoon})).join("+"))>0?"coming_soon":"",this.resultData.DESCRIPTION&&(this.resultData.descriptionBlurb=this.resultData.DESCRIPTION.substring(0,this.configuration.descriptionBlurb||120),this.resultData.descriptionRest=this.resultData.DESCRIPTION.substring(this.configuration.descriptionBlurb||120),this.resultData.descriptionFull=this.resultData.descriptionBlurb+this.resultData.descriptionRest),this.resultData.skinTypeText="undefined"!=typeof productPage&&"function"==typeof productPage.getAllSkinTypes?productPage.getAllSkinTypes(this.resultData):"",void 0!==this.resultData.ATTRIBUTE_BENEFIT&&(this.resultData.attrBenefit=this.resultData.ATTRIBUTE_BENEFIT.toString().replace(/,/g,", "))},formatPriceRange:function(){for(var e=this.resultData.skus[0],t=this.resultData.skus[0],s=0;st.PRICE?i:t}return e!==t?e.formattedPrice+" - "+t.formattedPrice:this.resultData.skus[0].formattedPrice},setupQuickShop:function(){var e=this.node.find("a.quickshop-link");if(e&&"undefined"!=typeof brx){var t=this;e.bind("click",(function(e){if(e.preventDefault(),jQuery.isFunction(productPage.launchQuickshop)){var s=jQuery(this).attr("id").replace("quickview-link-","");productPage.launchQuickshop(s)}else brx.productView.quickshop({productData:t.resultData})})),e.bind("mouseover",(function(e){jQuery(this).find(".quickshop-btn").addClass("qs-active"),jQuery(this).closest(".result").addClass("qs")})),e.bind("mouseout",(function(e){jQuery(this).find(".quickshop-btn").removeClass("qs-active"),jQuery(this).closest(".result").removeClass("qs")}))}},setupAddToBag:function(e){var t="number"==typeof e?e:e.SKU_BASE_ID,s=this.node.find("a.btn-add-to-bag"),i=this.node.find("span.add-progress");s.unbind(),s.attr("data-skubaseid",t),s.bind("click",(function(e){e.preventDefault(),i.length&&(s.hide(),i.show(),$(document).one("addToCart.success addToCart.failure",(function(){i.hide(),s.show()}))),site.addToCart({skuBaseId:$(this).attr("data-skubaseid")})}))},setupNote:function(){},setupGiftSetComponents:function(){},setupShades:function(){var e=this.node.find(".shades"),t=this.node.find(".selected-shade-name"),s=this.node.find(".shade-price");if(e.length){var i;i=void 0!==this.configuration.maxmimumShades&&this.resultData.skus.length>this.configuration.maxmimumShades?this.resultData.skus.slice(0,this.configuration.maxmimumShades):this.resultData.skus.slice(0),e.addClass("shades_"+this.resultData.skus.length);for(var n=0;n");n.css({"background-color":s[i]}),0==i&&n.addClass("first"),i==s.length-1&&n.addClass("last"),1==s.length&&n.addClass("single"),t.append(n)}t.css("width","auto")}},initListeners:function(e){this.node.on("click",this,(function(e){e.data.selectShade()}))},selectShade:function(e){this.node.siblings(".shade").removeClass("active"),this.node.addClass("active"),this.node.trigger("select.sku",this)}},site.endeca.result.shade=generic.endeca.result.shade,site.endeca.result.size={initialize:function(e){this._super(e),this.templatePath="/templates/endeca/products/size.tmpl",this.displayResult()},displayResultCallback:function(e){this.initListeners()},initListeners:function(e){this.node.on("click",this,(function(e){var t=e.data;this.node.trigger("select.sku",t)}))}},generic.endeca.result.summary={displayResult:function(e){e=e||{};var t=jQuery.extend({results:"/templates/endeca/summary/results.tmpl",noResults:"/templates/endeca/summary/no-results.tmpl",noTerm:"/templates/endeca/summary/no-term.tmpl",autoCorrect:"/templates/endeca/summary/auto-correct.tmpl",didYouMean:"/templates/endeca/summary/did-you-mean.tmpl"},this.configuration.templatePaths||{});""==this.resultData.searchTerm?this.templatePath=t.noTerm:this.hasResults?(this.templatePath=t.results,this.resultData.productAnchorLinkDisplay=this.resultData.totalProductRecords>0?"inline":"none",this.resultData.contentAnchorLinkDisplay=this.resultData.totalContentRecords>0?"inline":"none",this.resultData.productResultText+=this.resultData.totalContentRecords>0?",":""):this.templatePath=t.noResults,this._super(e);var s=this.node.find(".searchTerms");if(this.resultData.breadcrumbs&&s.length){for(var i=[],n=0;n");d.css({"background-color":e[t]}),0==t&&d.addClass("first"),t==e.length-1&&d.addClass("last"),1==e.length&&d.addClass("single"),a.append(d)}a.css("width","auto")}}}); ; jQuery(document).ready((function(){site.endeca.configuration={query:{MDEXHost:"localhost",MDEXPort:Drupal?.settings?.endeca?.ports?Drupal?.settings?.endeca?.ports?.mdex:{en_US:26410,en_CA:26410,fr_CA:26415,zh_CN:26435,de_DE:26445,fr_FR:26450,de_AT:26455,he_IL:26440,en_AU:26460,es_MX:26465,ja_JP:26470,ko_KR:26475,pt_BR:26480,nl_NL:26485,fr_BE:26490,nl_BE:26495,zh_TW:16401,tr_TR:16411,it_IT:16416,no_NO:16421,ru_RU:16426,th_TH:16431,es_ES:16436,de_CH:16441,fr_CH:16446},logHost:"localhost",logPort:Drupal?.settings?.endeca?.ports?Drupal?.settings?.endeca?.ports?.log:{en_US:26414,en_CA:26414,fr_CA:26419,zh_CN:26439,de_DE:26449,fr_FR:26454,de_AT:26459,he_IL:26444,en_AU:26464,es_MX:26469,ja_JP:26474,ko_KR:26479,pt_BR:26484,nl_NL:26489,fr_BE:26494,nl_BE:26499,zh_TW:16402,tr_TR:16412,it_IT:16417,no_NO:16422,ru_RU:16427,th_TH:16432,es_ES:16437,de_CH:16442,fr_CH:16447},defaultDimensionIds:[8061,8062,8127,8050,8063,8053,8089,8051,8095,8096,8147,8052,8054,8157],configuredRangeFilters:{skuShoppable:"s_shoppable|GT+0",skuPromotional:"s_promotional|GT+0",skuSearchable:"s_searchable|GT+0",productTrFlag:"p_TR_FLAG|LT+1",productDisplayable:"p_displayable|GT+0",productShoppable:"p_shoppable|GT+0"},defaultRangeFilters:["skuSearchable"],configuredRecordFilters:{products:"rec_type:product",content:"rec_type:content",locale:"locale:"+(jQuery.cookie("LOCALE")||Drupal?.settings?.endeca?.locale||"en_US"),activeSkus:"NOT(s_INVENTORY_STATUS:5)",discontinued:"NOT(s_discontinued:1)",shoppableOrComingSoon:"OR(s_shoppable:1,s_isComingSoon:1)"}},coremetricsEnabled:!0,omnitureEnabled:!0,contentzones:{},mixins:{}}})); ; site.endeca.coremetrics=jQuery.extend(!0,{},generic.endeca.coremetrics,{category_id:"search",page_id:"Search Results",dimensionNameMap:{"Skin Type":"Typ","Skin Tone":"Ton"}}); ; var site=site||{};site.endeca=site.endeca||{},site.endeca.instances=site.endeca.instances||{},site.endeca.instances.foundation_finder_dashboard=site.endeca.instances.foundation_finder_dashboard||{},site.endeca.instances.foundation_finder_dashboard.control=site.endeca.generic.Class.create(site.endeca.control,{initialize:function(t,s){this._super(t),this.queryString=this.queryString||s,this.nodes.resultsContainer.length&&(this.queryString?this.search():this.displayResults())},searchCompleted:function(){if(this._super()){this.results.products.resultData=[this.catalogs.product.resultList[0]],this.results.products.displayResults(),this.results.products.show(),this.processCoremetrics({productData:this.results.products.resultData}),this.hasResults=!0,this.displayResults()}},processCoremetrics:function(t){t=t||{productData:[]};if("function"==typeof cmCreatePageviewTag)for(var s=0;s=t.configuration.minSearchLength&&(e+="*",t.searchTerm=e,t.search({searchTerm:e}))}),175)},_watchToClose:function(){jQuery(document).on("click",this,(function(e){var s=e.target,t=e.data;jQuery(s).parents(t.nodes.wrapper.selector).length||s===t.currentInputElement||s===t.nodes.wrapper[0]||t.nodes.wrapper.addClass("hidden")}))},searchCompleted:function(){if(this._super()){if(this.queries?.product?.jsonResult?.AggrRecords?.length){for(var e={},s=[],t=0;tthis.results.terms.configuration.limit&&s.splice(this.results.terms.configuration.limit),s.sort((function(s,t){return e[s]>e[t]?-1:e[s]'+n+' ('+this.meta.searchInfo.totalRecords+")",url:this.configuration.fullSearchBaseUrl+a}],this.results.seeResults.displayResults(),this.results.seeResults.displayResultNodes(),this.results.seeResults.show(),this.nodes.wrapper.removeClass("hidden")}this.nodes.wrapper.find(".result").on("click",(function(){return $(this.parentElement).hasClass("js-typeahead-gap-tag")&&site.endeca.omniture.productClick(),!0})),this.processOmniture(),this.hideLoading()}}}); ; var site=site||{};site.endeca=site.endeca||{},site.endeca.instances=site.endeca.instances||{},site.endeca.instances.typeahead=site.endeca.instances.typeahead||{},jQuery(document).ready((function(){site.endeca.instances.typeahead.configuration=jQuery.extend(!0,{},site.endeca.configuration,{searchType:"typeahead",followRedirects:!1,minSearchLength:3,fullSearchBaseUrl:"/"+Drupal.settings.pathPrefix+"esearch?search=",nodes:{wrapper:jQuery("#typeahead-wrapper"),inputElements:jQuery(".predictive-search .search-term"),loading:jQuery(".loading","#typeahead-wrapper")},queries:{product:{recordsPerPage:5,recordFilters:["discontinued","activeSkus","products"],rangeFilters:["skuShoppable"]}},results:{products:{baseClass:"site.endeca.results",instanceArgs:{parentNode:jQuery(".product-results","#typeahead-wrapper"),childTemplatePath:"/templates/endeca/typeahead/product-result.tmpl",childTemplatePathSku:"/templates/endeca/typeahead/product-sku-result.tmpl"},configuration:{limit:5}},terms:{baseClass:"site.endeca.results",instanceArgs:{parentNode:jQuery(".term-results","#typeahead-wrapper"),templatePath:"/templates/endeca/typeahead/term-result.tmpl"},configuration:{limit:2}},seeResults:{baseClass:"site.endeca.results",instanceArgs:{parentNode:jQuery(".see-results","#typeahead-wrapper"),templatePath:"/templates/endeca/typeahead/term-result.tmpl"}}}}),new site.endeca.instances.typeahead.control(site.endeca.instances.typeahead.configuration)})); ; var site = site || {}; var generic = generic || {}; // Global variables var profileRequests = new Array; /** * Class used to handle site profiling, which involves the getting, the possible setting and the possible processing * of a user's attributes into tailored content or data for a page. * Public methods can be used then used to handle specific overall scenarios for a pages profiling. * Example: Setting touts on a page based on user defined skin type. * The profile_user config defines that rules that are ingested by this class on page load. * The class first looks for the config info in page_data and then will fire an rpc call if not found. * Arguments can be passed when initiating the class but not required. * @methodOf site */ site.profile = function( args ) { /**** Global vars ****/ var options = jQuery.extend( args, { setStorage : (args && args.setStorage) ? args.setStorage : true }); var storage = {}; var hasStorage = function() { return jQuery.isEmptyObject(storage) ? false : true; }; /**** Global classes and functions ****/ /** * Private class used to not only store the config data but also help with retrieving * specific attributes and rules also. * @method load: * - Grabs the profile config from the page and stores it when not available. * - Also set the internal config obj to be used later by _getData. * @method attr: * - Used to get specific attributes for the profile config. * - An optional sub param can be set to return a value one level down of the attribute obj. * @method rule: * - Same as the attr method except used to get specific attributes for the profile config. * - An optional sub param can be set to return a value one level down of the rules obj. * @returns {Object} The individual config objects and helper functions. * @private */ var _config = function() { var config = {}; // Helper methods that get passed with the data obj being requested. var _helpers = { get : function(key) { return this[key]; } }; var _getData = function(type, key, sub) { var data = config[type]; if (data) { // Return key config info based on sub or return {} if no key exists. var obj = data[key] ? sub ? data[key][sub] : data[key] : {}; jQuery.extend(obj, _helpers); return obj; } else { return {}; }; }; return { attr : function(key, sub) { return _getData('attributes', key, sub); }, rule : function(key, sub) { return _getData('rules', key, sub); }, load : function() { // Look for rules data object first in cached source, page data or cookie, or fire rpc call. if (jQuery.isEmptyObject(this.rules)) { var personalBlock = Drupal.settings.personal_block; var profileConfig = personalBlock ? personalBlock.profile_config : ''; if (profileConfig) { config = jQuery.extend(this, profileConfig); } else { console.log('PERSONALIZATION PROFILE_CONFIG NOT AVAILABLE'); } } else { // make rpc call to get rules if not in page source. }; } }; }(); /** * Private function used to handle the storage class. * site.profile defaults to having storage set to true but if not, this will * not set the global storage variable which stores the storage class. * If setStorage is set to true and the storage class isn't available, a * console message is posted. * @private */ var _setStorage = function() { if (!options.setStorage) { return false; }; if (site.profile.storage) { storage = site.profile.storage({ config : _config }); } else { console.log('Profile storage class is not loading.'); }; }; /** * Private function used to return an object from the API results to handle all the post API needs. * Each rules obj in the results array is wrapped with a set of default methods and any additional modifications. * Setter functions are also added to handle specific situations like * processing the rules output or map nodes to the rules obj. * All setter methods return the results array even if nothing is added to each rule obj. * @param {Array} results *REQUIRED* : Results array returned from the profile api. * @returns {Array} Array of results object from the api extended with helper functions. * @private */ var _setResultModifications = function(results) { if (!results) { return null; }; var origResults = results; // Define the default methods that will be added to the results obj. var defaultMethods = { getValue : function(key) { var value = (this[key] && this[key].value) ? this[key].value : '_'; return value; } } // Mapping of the defaultMethods to the global resultsArray with additional obj modifications. var resultsArray = jQuery.map( results, function(obj) { // Add rule param to the results object. var ruleId = obj.rule_id; if (ruleId) { for (var i in profileRequests) { if (ruleId === profileRequests[i].rule_id) { obj['rule_name'] = profileRequests[i].rule; break; }; }; }; // Extend the result object with the default methods. return jQuery.extend(obj, defaultMethods); }); return resultsArray; }; /** * Private class used for methods specific to calling the profile.process_rule rpc method. * @method call: * - Handles the actual calling to the api. * - Expects a set of params that can be used by calling this class and a callback. * - Callback is to be used for anything that needs to happen after the rules results have been processed. * - If the results from the filtering come back with rules that have all values stored, the json call is bypassed. * @method get: * - Handles the collecting of the results data that is already stored in the cache. * - Once the value is received from the cache, it is formatted to the correct obj format. * @method filter: * - Handles the filtering of the rules that have values in the cache. * - The rules that have all there values storage get pushed to the hasValues array and * those that don't have all there values, including dependencies, get pushed to noValues. * @method format: * - Handles the formatting of the params that will be passed to the API. * - Expects an array of DOM nodes that have the specific rule and data attributes. * - Returns a formatted obj that can be used for the profile API params. * @method analytics: * - Handles the storage of the results data and sending of rule data to analytics. * - During rule filtering and after the rpc call, each completed rule object gets pushed to analytics.data. * - Once everything is collected, which is determined if an RPC call is required or not, analytics.send is fired. * - @param {Array} data: The array containing all rule objects being pushed to the analytics engine. @ - @method send: Hook into the analytics engine which should pass the this.data object. * @private */ var _API = { call : function(array) { var rulesConfig = _config.rules; if (!rulesConfig || !array || !array[0]) { return null; }; var paramObj = { rules : array }; // Set an array of all rule's out_params to be used to filter out the rpc results. var outParams = []; jQuery(array).each( function() { var ruleConfig = this.name ? rulesConfig[this.name] : ''; var ruleOutParams = ruleConfig ? ruleConfig.out_params : ''; jQuery(ruleOutParams).each(function(i, param) { var insert = ($.inArray(param, outParams) >= 0) ? false : true; if (insert) { outParams.push(param); }; }); }); generic.jsonrpc.fetch({ method: 'profile.process_rule', params: [paramObj], onBoth: function(response) { var results = response.getValue(); var modResults = _setResultModifications(results); if (hasStorage() && modResults[0]) { // Filter out results that are only set as out_params in a rule. var filteredResultsObj = {}; jQuery(modResults).each( function(i, result) { _API.analytics.data.push(result); for (var key in result) { var insert = ($.inArray(key, outParams) >= 0) ? true : false; if (insert) { filteredResultsObj[key] = result[key]; }; }; }); storage.set(filteredResultsObj, true); }; jQuery(modResults).each(function(index, result) { jQuery(array).each( function(pIndex, param) { if (param.rule_id == result.rule_id) { if (param.callback) { param.callback(result); }; }; }); }); _API.analytics.send(); }, onError: function () { } }); }, setRequests : function() { if (!profileRequests || !profileRequests[0]) { return null; }; // Format requests for filtering var params = this.format(profileRequests); var filteredObj = this.filter(params); // Grab stored values var valuesArray = filteredObj.hasValues; var noValuesArray = filteredObj.noValues; var storedResults = valuesArray[0] ? this.get(valuesArray) : []; // If stored values exist, use the callback of each result. if (storedResults && storedResults[0]) { var modResults = _setResultModifications(storedResults); jQuery(modResults).each( function(index, result) { _API.analytics.data.push(result); if (result.callback) { result.callback(result); }; }); }; // If stored values don't exist, fire this.call to fetch values if (noValuesArray && noValuesArray[0]) { this.call(noValuesArray); } else { _API.analytics.send(); }; }, get : function(array) { if (!array && !array[0]) { return {}; }; var resultsArray = []; jQuery.each(array, function(index, rule) { var ruleName = rule.name; var rulesConfig = _config.rules; if (!ruleName || !rulesConfig) { return null; }; var resultObj = {}; var ruleInfo = rulesConfig[ruleName]; var outParams = ruleInfo ? ruleInfo.out_params : []; for (var param in rule) { if (param != 'name') { resultObj[param] = rule[param]; } }; jQuery(outParams).each( function(index, param) { var paramVal = ( hasStorage() && storage.hasValue(param) ) ? storage.get(param) : ''; if (paramVal) { resultObj[param] = { "value" : paramVal }; }; }); resultsArray.push(resultObj); }); return resultsArray; }, filter : function(array) { if (!array && !array[0]) { return {}; }; var valueArray = []; var filteredRules = []; jQuery(array).each(function(index, rule) { var ruleName = rule.name; var rulesConfig = _config.rules; if (!ruleName || !rulesConfig) { return null; }; // Make sure rules exists var ruleInfo = rulesConfig[ruleName]; if (!ruleInfo) { return null; }; var outParams = ruleInfo.out_params; var outParamsTotal = outParams.length; var valueCount = 0; if (!rule.force_call) { jQuery(outParams).each( function(index, param) { if (hasStorage() && storage.hasValue(param)) { valueCount++; }; }); }; if (valueCount != outParamsTotal) { var in_params = ruleInfo.in_params; // Add params to the rule unless none are already included. rule['params'] = rule['params'] ? jQuery.extend({}, rule['params']) : {}; jQuery(in_params).each(function(index, param) { // If storage is available and the param has any value. if (hasStorage() && storage.get(param)) { var sendValue = true; // If param has an expiration, check expiration otherwise send value. if (storage.getExp(param)) { // If param value has not expired, send value to rpc otherwise don't. sendValue = storage.hasValue(param) ? true : false; }; if (sendValue) { rule['params'][param] = storage.get(param); }; }; }); filteredRules.push(rule); } else { valueArray.push(rule); } }); return { hasValues : valueArray, noValues : filteredRules }; }, format : function(array) { if (!array || !array[0]) { return null; }; var rulesArray = []; jQuery(array).each( function(index, rule) { var name = rule.rule; var params = rule.params; var rule_id = rule.rule_id; var callback = rule.callback; var force_call = rule.force_call; // set up default rule param. var ruleObj = { 'name' : name }; // add data if available if (params) { ruleObj['params'] = params; }; // add id if available if (rule_id) { ruleObj['rule_id'] = rule_id; }; // add callback if available if (callback) { ruleObj['callback'] = callback; }; // add force_call if available if (force_call) { ruleObj['force_call'] = force_call; }; rulesArray.push(ruleObj); }); return rulesArray; }, analytics : { data : [], send : function() { // Spot to place analytics hook. tms_page_data['PSN'] = this.data; } } }; /** * Private function used to return the output defined by the profile_rules config. * Maps any output defined in rules config to each rules obj by looking for the path_base and out params in the results. * The path_base is first applied to the output and then the optional out params are added if available. * Once the output is determined, if permutations are defined, the getPermutations function * will return the permutation value from the profile_rules config, else it will return the original value. * @returns {String} The output set within the profile.config for the rule. * @private */ var _getOutput = function(obj) { var objRule = obj.rule; if (!objRule) { return null; }; var getPermutations = function(value) { var perm = permutations[value]; if (perm && perm['path']) { return perm['path']; } else { return value; }; }; var output = ''; var permutations = objRule.permutations; // Build output var defaultBasePath = _config.default_path_base; if (defaultBasePath) { output += defaultBasePath; }; var node = obj.node; if (node) { var nodeId = node.getAttribute('data-nid'); output += '/' + nodeId; } var pathBase = objRule.path_base; if (pathBase) { output += pathBase + '/'; }; // Add params based on param seq order. var outParams = objRule.out_params; if (outParams) { var pOutput = ''; jQuery(outParams).each(function(index, param) { var value = obj.getValue(param); if (value) { pOutput += ( index == 0 ) ? value : ( '/' + value ); }; }); var paramPath = permutations ? getPermutations(pOutput) : pOutput; output += paramPath; }; return output ? output : ''; } /**** Global initialization functions ****/ _config.load(); _setStorage(); /** @scope site.profile */ return { call : function(args) { return _API.call(args); }, setRequests : function() { _API.setRequests(); }, getConfig : function() { return _config; }, format : function(rulesArray) { return _API.format(rulesArray); }, getOutput : function(obj) { return _getOutput(obj); }, reset : function() { if (hasStorage()) { storage.reset(); } } } }; ; var site = site || {}; var generic = generic || {}; site.profile = site.profile || {}; /** * Class used to handle profile caching. * When available, site.profile will use this to store the attributes returned when a rule is processed or * check the cache for a specific attribute value when needed. * This class is using cookie storage but other types of storage will be explored (i.e. html5 storage). * @method get: * - Returns the value of a specific attribute set in the profile.config when available. * - Only returns values that are in the cache and not expired. * - If the value is expired or not set, it will return null. * - @param {String} key *REQUIRED* : Attribute name defined in profile.config * @method hasValue: * - Similar to get except returns a boolean instead of the value. * - @param {String} key *REQUIRED* : Attribute name defined in profile.config * @method set: * - Method used to set a data obj or array of data objects to storage. * - Does not take the expiration into account so this is a hard set. * - Once a value is passed, it will format that value into a scalar or array based on the attribute config. * - After the value is set, it is then sent to the cache. * - Example data object format: * { * 'SKIN_TYPE' : { * value : 3 * } * } * If a value obj isn't set to the attribute, it will not be passed to the cache storage. * - @param {Object} obj *REQUIRED* : Either an object or array of data objects that follows the format described. * @methodOf site.profile */ site.profile.storage = function( args ) { if (!args || !args.config) { return {}; }; /**** Global vars ****/ var config = args.config; /** * Class used to handle the data handling within a cookie. * Once the cookie is initialized, helper functions are used to set values stored * within the cookie. * The cookie is formatted in JSON after the value obj has been set using JSON.stringify. * In order to read or set a value or expiration in the cookie, JSON.parse is used to * convert the string value into a javascript obj. * Double quotes are also removed so the value size can be kept at a minimum. * @private */ var _cookie = { name : 'PSN', value : {}, attr : { path : "/", expires : 365 }, init : function() { if (!this.name) { return null; }; var userCookie = generic.cookie ? generic.cookie(this.name) : null; if (userCookie) { this.value = userCookie; } else { this.set(); }; }, currentTime : function() { var date = new Date(); // convert milliseconds to seconds return Math.floor(date.getTime() / 1000); }, hasExpired : function(key) { var expiration = this.getExpiration(key); return (this.currentTime() > expiration ) ? true : false; }, check : function() { // Makes sure cookie value is obj. var modVal = this.value; if (typeof modVal == 'string') { var cVal = modVal.replace(/\'/g, '"'); modVal = JSON.parse(cVal); this.value = modVal; }; return modVal; }, set : function(val) { var cookieVal = val || JSON.stringify(this.value); // Remove array escaping, spaces and double quotes. var match = cookieVal.replace(/\"\[/g, '['); match = match.replace(/\]\"/g, ']'); match = match.replace(/\\\"/g, '"'); match = match.replace(/^\s/g, ''); match = match.replace(/\"/g, "'"); if (generic.cookie) { generic.cookie(this.name, match, this.attr); } }, setKey : function(key, val, exp) { var keyAbbr = _getKeyAbbr(key); if (!key && !keyAbbr) { return null; }; this.init(); this.check(); this.value[keyAbbr] = {}; this.setValue(key, val); this.setExpiration(key, exp); this.set(); }, setValue : function(key, val) { var keyAbbr = _getKeyAbbr(key); if (!keyAbbr || !this.value[keyAbbr]) { return null; }; this.check(); this.value[keyAbbr]['v'] = val; this.set(); }, setExpiration : function(key, exp) { var keyAbbr = _getKeyAbbr(key); if (!keyAbbr || !this.value[keyAbbr]) { return null; }; this.check(); var newExp = exp ? (this.currentTime() + exp) : ''; this.value[keyAbbr]['t'] = newExp; this.set(); }, getValue : function(key) { this.check(); var keyObj = this.value[_getKeyAbbr(key)] || {}; return keyObj.v ? keyObj.v : null; }, getExpiration : function(key) { this.check(); var keyObj = this.value[_getKeyAbbr(key)] || {}; return keyObj.t ? keyObj.t : null; } }; /** * Private function used to return an attributes abbreviation (abbr) from the attribute config. * Passing the full key name will return the abbreviation or null. * @param {String} key *REQUIRED* : Name of the attribute set in profile.config. * @returns {String} The abbreviation of the attribute passed. * @private */ var _getKeyAbbr = function(key) { var attrConfig = config.attributes; if (!key || !attrConfig) { return null; }; return ( attrConfig[key] && attrConfig[key].abbr ) ? attrConfig[key].abbr : null; }; /** * Private function used to return a bolean value when an attribute value is set and not expired. * If either of those requirements are not set, false is returned. * The cache method getValue is first called to see if a value is set. * If a value is returned, the cache method hasExpired is then called to see if it needs to reset. * If the value has not expired, true is returned. * @param {String} key *REQUIRED* : Name of the attribute set in profile.config. * @returns {Boolean} Whether a value is available in the cache. * @private */ var _checkValue = function(key) { if (!key) { return false; }; var keyValue = _cookie.getValue(key); if (keyValue) { var expired = false; if (_cookie.hasExpired(key)) { expired = true; }; return expired ? false : true; } else { return false; }; }; /** * Private function used to set an attribute and reset any of it's dependent attributes. * The attribute key and value is passed along with an optional expiration when needed. * Once the key, value and optional expiration are sent to the cache obj, any dependencies * are checked for and if any are returned there expirations are voided. * This is done to make sure the rules are properly set with the most recent information. * @param {String} key *REQUIRED* : Name of the attribute set in profile.config. * @param {String} val : Value of the attribute to be set. * @param {Number} exp : Optional expiration value to be sent to the cache obj. * @private */ var _setKey = function(key, val, exp) { if (!key) { return null; }; _cookie.setKey(key, val, exp); var cacheConfig = config.attr(key, 'data').get('cache'); var dependencies = cacheConfig.dependencies; if (dependencies && dependencies[0]) { jQuery(dependencies).each( function(index, dKey) { if (_checkValue(dKey)) { _cookie.setExpiration(dKey, ''); }; }); }; }; /** * Private function that returns the attribute value if available. * After making sure a key is passed, it goes straight to the cache obj to retrieve the value else it returns null. * @param {String} key *REQUIRED* : Name of the attribute set in profile.config. * @returns {String/Number} The value of an attribute if available. * @private */ var _getValue = function(key) { if (!key) { return null; }; return _cookie.getValue(key); }; /** * Private function that returns the attribute expiration if available. * After making sure a key is passed, it goes straight to the cache obj to retrieve the expiration else it returns null. * @param {String} key *REQUIRED* : Name of the attribute set in profile.config. * @returns {String/Number} The expiration of an attribute if available. * @private */ var _getExpiration = function(key) { if (!key) { return null; }; return _cookie.getExpiration(key); }; /** * Private function used to filter the data object(s) passed to the public set method. * If the obj passed is not an array, the obj is placed within one to keep the interface flexible. * As each method is iterated through, it makes sure each obj attribute is an object and follows the format: * { * 'SKIN_TYPE' : { * value : 3 * } * } * This is done since some attributes of the obj might not be related to the actual value; example being a DOM node id. * If the object does, it with then check the attribute config to set the value formatting and then * pass that to the _setKey function to set the attribute and any attributes. * @param {Object} obj *REQUIRED* : Either an object or array of data objects that follows the format described. * @param {Boolean} isOutParam : Boolean passed to know when a call is fired from the JSON-RPC call. * @private */ var _setValues = function(obj, isOutParam) { if (!obj) { return null; }; var array = jQuery.isArray(obj) ? obj : [obj]; jQuery(array).each(function(index, resultObj) { for (var key in resultObj) { var result = resultObj[key]; if (typeof result == 'object' && result.value) { var attrConfig = config ? config.attr(key, 'data') : ''; var cacheConfig = jQuery.isEmptyObject(attrConfig) ? '' : attrConfig.get('cache'); if (cacheConfig && !jQuery.isEmptyObject(cacheConfig)) { var formattedVal = _formatValue(key, result.value, isOutParam); var expiration = isOutParam ? cacheConfig.expire : ''; _setKey(key, formattedVal, expiration); }; }; }; }); }; /** * Function used to format an attribute value by using the attribute data config. * Once an attribute key and value is passed, the attribute config is queried to see * if the attribute data config is set. * If the config is set and the config contains a type not a scalar, a switch is called to * handle the other types to get the formatting information. * A switch is used so other format types can be added without too much issue. * Here is an explanation of each type: * @type scalar (default): * - The easiest form of storage. * - It just sets that value to what is passed. * - No rules are applied at this point. * @type array: * - The array format type is used for attributes with multiple values, such as a list of category ids. * - The config data limit sets the size of the array while the data stack determines how the array is populated. * - An array limit is needed to be set in the config or a value will not be added to the array. * - Once the array is populated with the new value, it is then returned. * @returns {String/Number/Array} Newly formatted value. * @private */ var _formatValue = function(key, val, isOutParam) { if (!key || !val) { return null; }; var defaultVal = '_'; var dataConfig = config.attr(key, 'data'); var type = dataConfig.type; if (type && type != 'SCALAR') { var newVal = ''; switch(type) { case 'ARRAY': var keyVal = _cookie.getValue(key); var cacheInfo = dataConfig.get('cache'); var replaceVal = (cacheInfo.replace_on_out_param && isOutParam) ? true : false; if (keyVal && !replaceVal) { var insert = true; var modVal = (typeof keyVal == 'string') ? JSON.parse(keyVal) : keyVal; if (dataConfig.unique) { // If unique is set, add new value to array only if it's not there already. insert = ($.inArray(val, keyVal) >= 0) ? false : true; }; if (insert) { var arrayLimit = dataConfig.limit; // Replace initial value if it's default. modVal = ( modVal[0] == defaultVal ) ? [] : modVal; if ( jQuery.isArray(val) ) { // Merge the arrays if the val is also an array. jQuery.merge(modVal, val); } else { // Unshift the val when it is a string or int. modVal.unshift(val); } // Check the for the array limit if it is set in the config. if ( arrayLimit && (modVal.length > arrayLimit) ) { var stack = dataConfig.stack; if (!stack || stack == 'FIFO') { modVal = modVal.splice(0, arrayLimit); }; }; }; newVal = modVal; } else { if (jQuery.isArray(val)) { newVal = val; } else { var array = new Array(); array.push(val); newVal = array; }; }; break; }; return newVal; } else { return val; }; }; /** * Function used to reset the entire storage cache and not a single attribute. * Used for scenarios when the cache needs to be reset for maybe a new user at a * kiosk or a scenario involving sign-in/sign-out that requires a storage reset. * After instantiating site.profile, you can call this when needed. * @private */ var _reset = function() { // Just pass a single space to reset the cache. _cookie.set(' '); }; /** * Function to remove an attribute value and timestamp stored in the PSN front-end storage. * Used to force the backend to reprocess an attribute by looking at the backend storage when a rule is called. * Calls _setKey() and passes only the attribute name, to reset the attribute. * @param {keys} array or string *REQUIRED* : Either a string or array of attributes values to remove. */ var _deleteValues = function(keys) { if (!keys) { return null; }; var array = jQuery.isArray(keys) ? keys : [keys]; jQuery(array).each(function(index, key) { // If attribute exists in cookie, reset it. if (_getValue(key)) { // Reset the value and expiration to force reprocessing. _setKey(key, '', ''); }; }); }; /** * Function to reset the timestamp of an attribute stored in the PSN front-end storage. * Used to resend the stored attribute value to the backend for reprocessing. * Calls _setKey() and passes the attribute name and value if exists in storage already to reset the attribute. * @param {keys} array or string *REQUIRED* : Either a string or array of attributes to reset. */ var _expireValues = function(keys) { if (!keys) { return null; }; var array = jQuery.isArray(keys) ? keys : [keys]; jQuery(array).each(function(index, key) { var val = _getValue(key); // If attribute exists in cookie, reset it. if (val) { // Reset the value and expiration to force reprocessing. _setKey(key, val, ''); }; }); }; // Init cookie class. _cookie.init(); /** @scope site.profile.storage */ return { get : function(key) { return _getValue(key); }, getExp : function(key) { return _getExpiration(key); }, hasValue : function(key) { return _checkValue(key); }, deleteValues : function(keys) { _deleteValues(keys); }, expireValues : function(keys) { _expireValues(keys); }, set : function(obj, isOutParam) { _setValues(obj, isOutParam); }, reset : function() { _reset(); } } }; ; var site = site || {}; var generic = generic || {}; site.profile = site.profile || {}; /** * Class used to handle event setting for a rule attribute. * After an event, say a page view or quiz completion, this class allows you to pass an * attribute to the profile cache for future processing. * Once a value is stored, it will be sent for processing if a rule that uses that attribute is called. * @method store: * - The store method is the public method available to pass that attribute value. * - You can send either a value obj or an array of value objects in the following format: * { 'SKIN_TYPE' : 3 } * - Once the value is sent, it will be formatted as per the site.profile class requirements and sent * for validation and processing. * - @param {Object} obj *REQUIRED* : Either an object or array of data objects that follows the format described above. * @methodOf site.profile */ site.profile.events = function( args ) { /**** Global vars ****/ var options = jQuery.extend(args, {}); var profile = site.profile(); var config = {}; var storage = {}; /** * Load function used to store the config and storage object. * If either aren't loaded, they will load there respective classes. * The config object will either call the profile class or the global profile_config variable. * If the storage object isn't loaded, the site.profile.storage will be called. * @private */ var _load = function() { if (jQuery.isEmptyObject(config)) { config = profile.getConfig() || profile_config; }; if (jQuery.isEmptyObject(storage)) { storage = site.profile.storage ? site.profile.storage({ config : config }) : {}; }; }; /** * Function used to format and return the object passed to the public method following * the requirements of the site.profile class. * Example: * Converts: * { * 'SKIN_TYPE' : 3 * } * to: * { * 'SKIN_TYPE' : { * 'value' : 3 * } * } * @returns {Object} Newly formatted object. * @private */ var _format = function(obj) { if (!obj) { return null; }; var newObj = {}; for (var key in obj) { newObj[key] = { value : obj[key] }; }; return newObj; }; /** * Function used to check if the data value obj passed is not empty and then * call the storage set method if storage is available. * @private */ var _callStorage = function(obj) { if (jQuery.isEmptyObject(obj)) { return null; }; if (!jQuery.isEmptyObject(storage)) { storage.set(obj); }; }; /** * Function used to check if the data obj passed is an array or object and * then call the _callStorage function to store the attribute value. * _load is called before to make sure the storage is set properly. * @private */ var _store = function(obj) { if (!obj) { return null; }; _load(); if (jQuery.isArray(obj)) { jQuery(obj).each(function(index, obj) { _callStorage(_format(obj)); }); } else { _callStorage(_format(obj)); }; }; /** * Function used to remove the stored attribute value by calling the storage.deleteValues method. * Deleting an attribute clears the value and expiration so when a rule is called, * the attribute will processed on the backend. * _load is called before to make sure the storage is set properly. * @private */ var _delete = function(keys) { if (!keys) { return null; }; _load(); storage.deleteValues(keys); }; /** * Function used to expire an attribute Value by calling the storage.expireValues method. * Resetting an attribute timestamp clears the expiration so when a rule is called, * the stored attribute will processed on the backend. * _load is called before to make sure the storage is set properly. * @private */ var _expire = function(keys) { if (!keys) { return null; }; _load(); storage.expireValues(keys); }; // Init classes needed for events. _load(); /** @scope site.profile.events */ return { store : function(obj) { _store(obj); }, expire : function(keys) { _expire(keys); }, del : function(keys) { _delete(keys); } } };; var site = site || {}; var generic = generic || {}; site.profile = site.profile || {}; /** * Class used to handle the population of profile touts. * @method set: * - Handles populating specific DOM nodes with touts based on the rule set in the 'data-profile-rule' attribute. * - Uses site.profile to gather the specific data of a user based on that * attribute and then process the results to determine the correct touts. * - @param {String} data-profile-rule *REQUIRED* : Rule used for that tout. Rules are set in the profile.tmpl config. * - @param {Object} data-profile-options : Used to override the results for testing or if that rule info is * already determined before firing site.profile. Needs to be JSON formatted. Example '{ "SKIN_TYPE" : 3 }' * @methodOf site.profile */ site.profile.touts = function( args ) { /**** Global vars ****/ var options = args || {}; var profile = site.profile(); var config = profile.getConfig(); /** * Private class used for methods specific to handling DOM nodes. * @method get: * - Gets all the DOM nodes that use the attribute defined on method load and returns the array. * - Uses global options.ruleAttr and if nothing is matched, will return an empty array. * - @param {String} ruleAttr *REQUIRED* : Unique DOM node id used to collect rule specific nodes. * @method parse: * - Handles the extracting of the rules and rules data from the DOM nodes. * - Iterates through each node and creates an array of rules obj to use where needed. * - Returns an array unless an array of DOM nodes or a ruleAttr is not defined in options. * - @param {Array} nodes *REQUIRED* : Array of DOM nodes that will be used to generate the rules object array. * - @param {String} ruleAttr *REQUIRED* : Unique DOM node id used to collect rule specific nodes. * - @param {String} dataAttr : Optional attribute added to each rule node that can be used to override values. * - @returns {Array} Array of dom node objects that contain rules. * @method set: * - Used by the public method 'set' to handle the setting of DOM nodes. * - The profile DOM nodes are first collected then a params obj is created to submit to site.profile assigned to profile. * - Once the results are returned, the DOM info is mapped back to the data. * - Next, the DOM is then populated with the correct touts based on the rules used to define the output. * - @param {Obj} args *REQUIRED* : Object arguments used by this.get to determine which DOM nodes to capture. * @private */ var _nodes = { get : function() { var ruleAttr = options.ruleAttr; if (!ruleAttr) { return null; }; var nodes = jQuery('[' + ruleAttr + ']'); return nodes; }, parse : function(nodes) { var ruleAttr = options.ruleAttr; var dataAttr = options.dataAttr; if ( !nodes || !nodes[0] || !ruleAttr ) { return null; }; var rulesArray = []; jQuery(nodes).each( function(index, node) { var ruleId = node.getAttribute('data-rule-id'); var rulesObj = { 'node' : node, 'rule' : node.getAttribute(ruleAttr), 'rule_id' : ruleId, 'callback' : function(result) { var resultsMatch = _addNodeInfo(nodes, result); _populateDOM(resultsMatch); } }; if (dataAttr) { // expects json formatting var attr = dataAttr.replace("data-",""); rulesObj['data'] = jQuery(node).data(attr); }; rulesArray.push(rulesObj); }); return jQuery(rulesArray); }, set : function(args) { if (!args) { return null; }; jQuery.extend(options, args); var nodes = this.get(args); var rulesArray = this.parse(nodes); jQuery(rulesArray).each( function(index, rule) { profileRequests.push(rule); }); profile.setRequests(); } }; /** * Private function used to map each DOM node with a rule to the rules results. * Does the mapping by matching the node id of the nodes passed into the function with * the id in the obj returned from the API. * If a match is made, the node and rule are added to the original obj result obj. * If no object is matched, the original object is just passed back. * @param {Array} nodes *REQUIRED* : Set of DOM nodes in an array used to match with the API results. * @param {Array} results *REQUIRED* : Global results array containing the rules returned from the API. * @returns {Object} A result object passed from the API extended with the node info for mapping. * @private */ var _addNodeInfo = function(nodes, results) { if (!nodes || !results) { return null; }; // Add results to an array if it's a single obj. var results = jQuery.isArray(results) ? results : [results]; return jQuery.map(results, function(obj) { // Assign result object to a node if available if (nodes && nodes[0]) { jQuery(nodes).each(function(index, node) { var ruleId = node.getAttribute('data-rule-id'); if (ruleId == obj.rule_id) { var attr = options.ruleAttr.replace("data-",""); obj['node'] = this; obj['rule'] = config.rule(jQuery(node).data(attr)); obj['output'] = profile.getOutput(obj); }; }); }; return obj; }); } /** * Private function that ties into generic.templatefactory. * Returns a template that is then passed into a callback param. * @param {String} args.path *REQUIRED* : Path of the template to be retrieved. * @param {Function} args.callback *REQUIRED* : Functionality to be done after the template is fetched. * @param {Object} args.params : Optional params that can be passed into the template being fetched. * @private */ var _getTemplate = function(args) { var path = args.path; var callback = args.callback; var params = args.params || {}; if (!path || !callback) { return null; }; generic.template.get({ path : path, callback : callback }); }; /** * Private function specific to populating the DOM using the output defined each rules object. * Need to pass each rules object with the output defined, which assumes is a path. * The callback is set to replace the node defined in the result obj with the fetched template. * @param {String} args.output *REQUIRED* : Path of the template to be retrieved. * @private */ var _populateDOM = function(results) { if (!results) { return null; }; jQuery(results).each( function(index, result) { _getTemplate({ path : result.output, callback : function(json) { var jsonObj = ''; try { jsonObj = JSON.parse(json); } catch (e) { //console.log('PERSONAL_BLOCK::JSON is not valid'); return false; }; var html = jsonObj.html; var js = jsonObj.js; var node = result.node; if (node) { if (html) { jQuery(node).html(html); }; }; if (js) { // When js is available, append it to the body to re-initialize module js. var script = document.createElement("script"); script.type = "text/javascript"; try { jQuery(script).append(js); } catch (e) { //console.log('PERSONAL_BLOCK::JSON Block js not available.'); return false; }; document.body.appendChild(script); Drupal.attachBehaviors(); }; // Fix for carousel bug with attachBehaviors. var slideShowNodes = jQuery(node).find('.cycle-slideshow'); if (slideShowNodes[0]) { slideShowNodes.cycle(); }; } }); }); }; /** @scope site.profile.touts */ return { set : function(args) { _nodes.set(args); } } }; ; jQuery( function() { // Call the touts class on every page load. var userTouts = site.profile.touts(); userTouts.set({ ruleAttr : 'data-profile-rule', dataAttr : 'data-profile-options' }); }); ; window.matchMedia=window.matchMedia||function(d){var f,e=d.documentElement,h=e.firstElementChild||e.firstChild,k=d.createElement("body"),i=d.createElement("div");i.id="mq-test-1";i.style.cssText="position:absolute;top:-100em";k.style.background="none";k.appendChild(i);return function(d){i.innerHTML='­';e.insertBefore(k,h);f=42==i.offsetWidth;e.removeChild(k);return{matches:f,media:d}}}(document); (function(d){function f(){t(!0)}d.respond={};respond.update=function(){};respond.mediaQueriesSupported=d.matchMedia&&d.matchMedia("only all").matches;if(!respond.mediaQueriesSupported){var e=d.document,h=e.documentElement,k=[],i=[],l=[],q={},r=e.getElementsByTagName("head")[0]||h,E=e.getElementsByTagName("base")[0],s=r.getElementsByTagName("link"),u=[],A=function(){for(var c=s.length,b=0,a,m,g,e;bg-v)clearTimeout(C),C=setTimeout(t,30);else{v=g;for(var f in k){var c=k[f],g=c.minw,j=c.maxw,q=null===g,p=null===j;g&&(g=parseFloat(g)*(-1=g)&&(p||a<=j))b[c.media]||(b[c.media]=[]),b[c.media].push(i[c.rules])}for(f in l)l[f]&&l[f].parentNode===r&&r.removeChild(l[f]);for(f in b)a=e.createElement("style"), c=b[f].join("\n"),a.type="text/css",a.media=f,r.insertBefore(a,d.nextSibling),a.styleSheet?a.styleSheet.cssText=c:a.appendChild(e.createTextNode(c)),l.push(a)}},B,x=!1;try{x=new XMLHttpRequest}catch(F){x=new ActiveXObject("Microsoft.XMLHTTP")}B=function(){return x};A();respond.update=A;d.addEventListener?d.addEventListener("resize",f,!1):d.attachEvent&&d.attachEvent("onresize",f)}})(this); ; /*! Picturefill - v3.0.1 - 2015-09-30 * http://scottjehl.github.io/picturefill * Copyright (c) 2015 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */ !function(a){var b=navigator.userAgent;a.HTMLPictureElement&&/ecko/.test(b)&&b.match(/rv\:(\d+)/)&&RegExp.$1<41&&addEventListener("resize",function(){var b,c=document.createElement("source"),d=function(a){var b,d,e=a.parentNode;"PICTURE"===e.nodeName.toUpperCase()?(b=c.cloneNode(),e.insertBefore(b,e.firstElementChild),setTimeout(function(){e.removeChild(b)})):(!a._pfLastSize||a.offsetWidth>a._pfLastSize)&&(a._pfLastSize=a.offsetWidth,d=a.sizes,a.sizes+=",100vw",setTimeout(function(){a.sizes=d}))},e=function(){var a,b=document.querySelectorAll("picture > img, img[srcset][sizes]");for(a=0;a2.7?h=c+1:(f=b-c,e=Math.pow(a-.6,1.5),g=f*e,d&&(g+=.1*e),h=a+g):h=c>1?Math.sqrt(a*b):a,h>c}function h(a){var b,c=s.getSet(a),d=!1;"pending"!==c&&(d=r,c&&(b=s.setRes(c),s.applySetCandidate(b,a))),a[s.ns].evaled=d}function i(a,b){return a.res-b.res}function j(a,b,c){var d;return!c&&b&&(c=a[s.ns].sets,c=c&&c[c.length-1]),d=k(b,c),d&&(b=s.makeUrl(b),a[s.ns].curSrc=b,a[s.ns].curCan=d,d.res||_(d,d.set.sizes)),d}function k(a,b){var c,d,e;if(a&&b)for(e=s.parseSet(b),a=s.makeUrl(a),c=0;cc;c++)e=g[c],e[s.ns]=!0,f=e.getAttribute("srcset"),f&&b.push({srcset:f,media:e.getAttribute("media"),type:e.getAttribute("type"),sizes:e.getAttribute("sizes")})}function m(a,b){function c(b){var c,d=b.exec(a.substring(m));return d?(c=d[0],m+=c.length,c):void 0}function e(){var a,c,d,e,f,i,j,k,l,m=!1,o={};for(e=0;el?m=!0:c=l):W.test(j)&&"h"===i?((d||c)&&(m=!0),0===k?m=!0:d=k):m=!0;m||(o.url=g,a&&(o.w=a),c&&(o.d=c),d&&(o.h=d),d||c||a||(o.d=1),1===o.d&&(b.has1x=!0),o.set=b,n.push(o))}function f(){for(c(S),i="",j="in descriptor";;){if(k=a.charAt(m),"in descriptor"===j)if(d(k))i&&(h.push(i),i="",j="after descriptor");else{if(","===k)return m+=1,i&&h.push(i),void e();if("("===k)i+=k,j="in parens";else{if(""===k)return i&&h.push(i),void e();i+=k}}else if("in parens"===j)if(")"===k)i+=k,j="in descriptor";else{if(""===k)return h.push(i),void e();i+=k}else if("after descriptor"===j)if(d(k));else{if(""===k)return void e();j="in descriptor",m-=1}m+=1}}for(var g,h,i,j,k,l=a.length,m=0,n=[];;){if(c(T),m>=l)return n;g=c(U),h=[],","===g.slice(-1)?(g=g.replace(V,""),e()):f()}}function n(a){function b(a){function b(){f&&(g.push(f),f="")}function c(){g[0]&&(h.push(g),g=[])}for(var e,f="",g=[],h=[],i=0,j=0,k=!1;;){if(e=a.charAt(j),""===e)return b(),c(),h;if(k){if("*"===e&&"/"===a[j+1]){k=!1,j+=2,b();continue}j+=1}else{if(d(e)){if(a.charAt(j-1)&&d(a.charAt(j-1))||!f){j+=1;continue}if(0===i){b(),j+=1;continue}e=" "}else if("("===e)i+=1;else if(")"===e)i-=1;else{if(","===e){b(),c(),j+=1;continue}if("/"===e&&"*"===a.charAt(j+1)){k=!0,j+=2;continue}}f+=e,j+=1}}}function c(a){return k.test(a)&&parseFloat(a)>=0?!0:l.test(a)?!0:"0"===a||"-0"===a||"+0"===a?!0:!1}var e,f,g,h,i,j,k=/^(?:[+-]?[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?(?:ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmin|vmax|vw)$/i,l=/^calc\((?:[0-9a-z \.\+\-\*\/\(\)]+)\)$/i;for(f=b(a),g=f.length,e=0;g>e;e++)if(h=f[e],i=h[h.length-1],c(i)){if(j=i,h.pop(),0===h.length)return j;if(h=h.join(" "),s.matchesMedia(h))return j}return"100vw"}b.createElement("picture");var o,p,q,r,s={},t=function(){},u=b.createElement("img"),v=u.getAttribute,w=u.setAttribute,x=u.removeAttribute,y=b.documentElement,z={},A={algorithm:""},B="data-pfsrc",C=B+"set",D=navigator.userAgent,E=/rident/.test(D)||/ecko/.test(D)&&D.match(/rv\:(\d+)/)&&RegExp.$1>35,F="currentSrc",G=/\s+\+?\d+(e\d+)?w/,H=/(\([^)]+\))?\s*(.+)/,I=a.picturefillCFG,J="position:absolute;left:0;visibility:hidden;display:block;padding:0;border:none;font-size:1em;width:1em;overflow:hidden;clip:rect(0px, 0px, 0px, 0px)",K="font-size:100%!important;",L=!0,M={},N={},O=a.devicePixelRatio,P={px:1,"in":96},Q=b.createElement("a"),R=!1,S=/^[ \t\n\r\u000c]+/,T=/^[, \t\n\r\u000c]+/,U=/^[^ \t\n\r\u000c]+/,V=/[,]+$/,W=/^\d+$/,X=/^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/,Y=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d||!1):a.attachEvent&&a.attachEvent("on"+b,c)},Z=function(a){var b={};return function(c){return c in b||(b[c]=a(c)),b[c]}},$=function(){var a=/^([\d\.]+)(em|vw|px)$/,b=function(){for(var a=arguments,b=0,c=a[0];++b in a;)c=c.replace(a[b],a[++b]);return c},c=Z(function(a){return"return "+b((a||"").toLowerCase(),/\band\b/g,"&&",/,/g,"||",/min-([a-z-\s]+):/g,"e.$1>=",/max-([a-z-\s]+):/g,"e.$1<=",/calc([^)]+)/g,"($1)",/(\d+[\.]*[\d]*)([a-z]+)/g,"($1 * e.$2)",/^(?!(e.[a-z]|[0-9\.&=|><\+\-\*\(\)\/])).*/gi,"")+";"});return function(b,d){var e;if(!(b in M))if(M[b]=!1,d&&(e=b.match(a)))M[b]=e[1]*P[e[2]];else try{M[b]=new Function("e",c(b))(P)}catch(f){}return M[b]}}(),_=function(a,b){return a.w?(a.cWidth=s.calcListLength(b||"100vw"),a.res=a.w/a.cWidth):a.res=a.d,a},aa=function(a){var c,d,e,f=a||{};if(f.elements&&1===f.elements.nodeType&&("IMG"===f.elements.nodeName.toUpperCase()?f.elements=[f.elements]:(f.context=f.elements,f.elements=null)),c=f.elements||s.qsa(f.context||b,f.reevaluate||f.reselect?s.sel:s.selShort),e=c.length){for(s.setupRun(f),R=!0,d=0;e>d;d++)s.fillImg(c[d],f);s.teardownRun(f)}};o=a.console&&console.warn?function(a){console.warn(a)}:t,F in u||(F="src"),z["image/jpeg"]=!0,z["image/gif"]=!0,z["image/png"]=!0,z["image/svg+xml"]=b.implementation.hasFeature("http://wwwindow.w3.org/TR/SVG11/feature#Image","1.1"),s.ns=("pf"+(new Date).getTime()).substr(0,9),s.supSrcset="srcset"in u,s.supSizes="sizes"in u,s.supPicture=!!a.HTMLPictureElement,s.supSrcset&&s.supPicture&&!s.supSizes&&!function(a){u.srcset="data:,a",a.src="data:,a",s.supSrcset=u.complete===a.complete,s.supPicture=s.supSrcset&&s.supPicture}(b.createElement("img")),s.selShort="picture>img,img[srcset]",s.sel=s.selShort,s.cfg=A,s.supSrcset&&(s.sel+=",img["+C+"]"),s.DPR=O||1,s.u=P,s.types=z,q=s.supSrcset&&!s.supSizes,s.setSize=t,s.makeUrl=Z(function(a){return Q.href=a,Q.href}),s.qsa=function(a,b){return a.querySelectorAll(b)},s.matchesMedia=function(){return a.matchMedia&&(matchMedia("(min-width: 0.1em)")||{}).matches?s.matchesMedia=function(a){return!a||matchMedia(a).matches}:s.matchesMedia=s.mMQ,s.matchesMedia.apply(this,arguments)},s.mMQ=function(a){return a?$(a):!0},s.calcLength=function(a){var b=$(a,!0)||!1;return 0>b&&(b=!1),b},s.supportsType=function(a){return a?z[a]:!0},s.parseSize=Z(function(a){var b=(a||"").match(H);return{media:b&&b[1],length:b&&b[2]}}),s.parseSet=function(a){return a.cands||(a.cands=m(a.srcset,a)),a.cands},s.getEmValue=function(){var a;if(!p&&(a=b.body)){var c=b.createElement("div"),d=y.style.cssText,e=a.style.cssText;c.style.cssText=J,y.style.cssText=K,a.style.cssText=K,a.appendChild(c),p=c.offsetWidth,a.removeChild(c),p=parseFloat(p,10),y.style.cssText=d,a.style.cssText=e}return p||16},s.calcListLength=function(a){if(!(a in N)||A.uT){var b=s.calcLength(n(a));N[a]=b?b:P.width}return N[a]},s.setRes=function(a){var b;if(a){b=s.parseSet(a);for(var c=0,d=b.length;d>c;c++)_(b[c],a.sizes)}return b},s.setRes.res=_,s.applySetCandidate=function(a,b){if(a.length){var c,d,e,f,h,k,l,m,n,o=b[s.ns],p=s.DPR;if(k=o.curSrc||b[F],l=o.curCan||j(b,k,a[0].set),l&&l.set===a[0].set&&(n=E&&!b.complete&&l.res-.1>p,n||(l.cached=!0,l.res>=p&&(h=l))),!h)for(a.sort(i),f=a.length,h=a[f-1],d=0;f>d;d++)if(c=a[d],c.res>=p){e=d-1,h=a[e]&&(n||k!==s.makeUrl(c.url))&&g(a[e].res,c.res,p,a[e].cached)?a[e]:c;break}h&&(m=s.makeUrl(h.url),o.curSrc=m,o.curCan=h,m!==k&&s.setSrc(b,h),s.setSize(b))}},s.setSrc=function(a,b){var c;a.src=b.url,"image/svg+xml"===b.set.type&&(c=a.style.width,a.style.width=a.offsetWidth+1+"px",a.offsetWidth+1&&(a.style.width=c))},s.getSet=function(a){var b,c,d,e=!1,f=a[s.ns].sets;for(b=0;bf?c=setTimeout(e,b-f):(c=null,a())};return function(){d=new Date,c||(c=setTimeout(e,b))}},h=y.clientHeight,i=function(){L=Math.max(a.innerWidth||0,y.clientWidth)!==P.width||y.clientHeight!==h,h=y.clientHeight,L&&s.fillImgs()};Y(a,"resize",g(i,99)),Y(b,"readystatechange",e)}(),s.picturefill=aa,s.fillImgs=aa,s.teardownRun=t,aa._=s,a.picturefillCFG={pf:s,push:function(a){var b=a.shift();"function"==typeof s[b]?s[b].apply(s,a):(A[b]=a[0],R&&s.fillImgs({reselect:!0}))}};for(;I&&I.length;)a.picturefillCFG.push(I.shift());a.picturefill=aa,"object"==typeof module&&"object"==typeof module.exports?module.exports=aa:"function"==typeof define&&define.amd&&define("picturefill",function(){return aa}),s.supPicture||(z["image/webp"]=e("image/webp","data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA=="))}(window,document);;