// ======= amplib js main ======= !function(n,l){"object"==typeof exports&&"undefined"!=typeof module?l(exports):"function"==typeof define&&define.amd?define(["exports"],l):l(n.preact={})}(this,function(n){var l,u,t,i,o,f,r,e={},c=[],s=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord/i;function a(n,l){for(var u in l)n[u]=l[u];return n}function h(n){var l=n.parentNode;l&&l.removeChild(n)}function p(n,l,u){var t,i=arguments,o={};for(t in l)"key"!==t&&"ref"!==t&&(o[t]=l[t]);if(arguments.length>3)for(u=[u],t=3;t2&&(l.children=c.slice.call(arguments,2)),v(n.type,l,l.key||n.key,l.ref||n.ref)},n.createContext=function(n){var l={},u={__c:"__cC"+r++,__:n,Consumer:function(n,l){return n.children(l)},Provider:function(n){var t,i=this;return this.getChildContext||(t=[],this.getChildContext=function(){return l[u.__c]=i,l},this.shouldComponentUpdate=function(l){n.value!==l.value&&t.some(function(n){n.context=l.value,g(n)})},this.sub=function(n){t.push(n);var l=n.componentWillUnmount;n.componentWillUnmount=function(){t.splice(t.indexOf(n),1),l&&l.call(n)}}),n.children}};return u.Consumer.contextType=u,u},n.toChildArray=b,n._e=A,n.options=l}); //# sourceMappingURL=preact.umd.js.map let e = preact.createElement; !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";var e,i;function c(){return e.apply(null,arguments)}function o(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function u(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function l(e){return void 0===e}function h(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function d(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function f(e,t){var n,s=[];for(n=0;n>>0,s=0;sSe(e)?(r=e+1,o-Se(e)):(r=e,o),{year:r,dayOfYear:a}}function Ie(e,t,n){var s,i,r=Ve(e.year(),t,n),a=Math.floor((e.dayOfYear()-r-1)/7)+1;return a<1?s=a+Ae(i=e.year()-1,t,n):a>Ae(e.year(),t,n)?(s=a-Ae(e.year(),t,n),i=e.year()+1):(i=e.year(),s=a),{week:s,year:i}}function Ae(e,t,n){var s=Ve(e,t,n),i=Ve(e+1,t,n);return(Se(e)-s+i)/7}I("w",["ww",2],"wo","week"),I("W",["WW",2],"Wo","isoWeek"),C("week","w"),C("isoWeek","W"),F("week",5),F("isoWeek",5),ue("w",B),ue("ww",B,z),ue("W",B),ue("WW",B,z),fe(["w","ww","W","WW"],function(e,t,n,s){t[s.substr(0,1)]=D(e)});function je(e,t){return e.slice(t,7).concat(e.slice(0,t))}I("d",0,"do","day"),I("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),I("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),I("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),I("e",0,0,"weekday"),I("E",0,0,"isoWeekday"),C("day","d"),C("weekday","e"),C("isoWeekday","E"),F("day",11),F("weekday",11),F("isoWeekday",11),ue("d",B),ue("e",B),ue("E",B),ue("dd",function(e,t){return t.weekdaysMinRegex(e)}),ue("ddd",function(e,t){return t.weekdaysShortRegex(e)}),ue("dddd",function(e,t){return t.weekdaysRegex(e)}),fe(["dd","ddd","dddd"],function(e,t,n,s){var i=n._locale.weekdaysParse(e,s,n._strict);null!=i?t.d=i:g(n).invalidWeekday=e}),fe(["d","e","E"],function(e,t,n,s){t[s]=D(e)});var Ze="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_");var ze="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_");var $e="Su_Mo_Tu_We_Th_Fr_Sa".split("_");var qe=ae;var Je=ae;var Be=ae;function Qe(){function e(e,t){return t.length-e.length}var t,n,s,i,r,a=[],o=[],u=[],l=[];for(t=0;t<7;t++)n=y([2e3,1]).day(t),s=this.weekdaysMin(n,""),i=this.weekdaysShort(n,""),r=this.weekdays(n,""),a.push(s),o.push(i),u.push(r),l.push(s),l.push(i),l.push(r);for(a.sort(e),o.sort(e),u.sort(e),l.sort(e),t=0;t<7;t++)o[t]=he(o[t]),u[t]=he(u[t]),l[t]=he(l[t]);this._weekdaysRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+a.join("|")+")","i")}function Xe(){return this.hours()%12||12}function Ke(e,t){I(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function et(e,t){return t._meridiemParse}I("H",["HH",2],0,"hour"),I("h",["hh",2],0,Xe),I("k",["kk",2],0,function(){return this.hours()||24}),I("hmm",0,0,function(){return""+Xe.apply(this)+L(this.minutes(),2)}),I("hmmss",0,0,function(){return""+Xe.apply(this)+L(this.minutes(),2)+L(this.seconds(),2)}),I("Hmm",0,0,function(){return""+this.hours()+L(this.minutes(),2)}),I("Hmmss",0,0,function(){return""+this.hours()+L(this.minutes(),2)+L(this.seconds(),2)}),Ke("a",!0),Ke("A",!1),C("hour","h"),F("hour",13),ue("a",et),ue("A",et),ue("H",B),ue("h",B),ue("k",B),ue("HH",B,z),ue("hh",B,z),ue("kk",B,z),ue("hmm",Q),ue("hmmss",X),ue("Hmm",Q),ue("Hmmss",X),ce(["H","HH"],ge),ce(["k","kk"],function(e,t,n){var s=D(e);t[ge]=24===s?0:s}),ce(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),ce(["h","hh"],function(e,t,n){t[ge]=D(e),g(n).bigHour=!0}),ce("hmm",function(e,t,n){var s=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s)),g(n).bigHour=!0}),ce("hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s,2)),t[pe]=D(e.substr(i)),g(n).bigHour=!0}),ce("Hmm",function(e,t,n){var s=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s))}),ce("Hmmss",function(e,t,n){var s=e.length-4,i=e.length-2;t[ge]=D(e.substr(0,s)),t[ve]=D(e.substr(s,2)),t[pe]=D(e.substr(i))});var tt,nt=Te("Hours",!0),st={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Ce,monthsShort:He,week:{dow:0,doy:6},weekdays:Ze,weekdaysMin:$e,weekdaysShort:ze,meridiemParse:/[ap]\.?m?\.?/i},it={},rt={};function at(e){return e?e.toLowerCase().replace("_","-"):e}function ot(e){var t=null;if(!it[e]&&"undefined"!=typeof module&&module&&module.exports)try{t=tt._abbr,require("./locale/"+e),ut(t)}catch(e){}return it[e]}function ut(e,t){var n;return e&&((n=l(t)?ht(e):lt(e,t))?tt=n:"undefined"!=typeof console&&console.warn&&console.warn("Locale "+e+" not found. Did you forget to load it?")),tt._abbr}function lt(e,t){if(null===t)return delete it[e],null;var n,s=st;if(t.abbr=e,null!=it[e])T("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),s=it[e]._config;else if(null!=t.parentLocale)if(null!=it[t.parentLocale])s=it[t.parentLocale]._config;else{if(null==(n=ot(t.parentLocale)))return rt[t.parentLocale]||(rt[t.parentLocale]=[]),rt[t.parentLocale].push({name:e,config:t}),null;s=n._config}return it[e]=new P(x(s,t)),rt[e]&&rt[e].forEach(function(e){lt(e.name,e.config)}),ut(e),it[e]}function ht(e){var t;if(e&&e._locale&&e._locale._abbr&&(e=e._locale._abbr),!e)return tt;if(!o(e)){if(t=ot(e))return t;e=[e]}return function(e){for(var t,n,s,i,r=0;r=t&&a(i,n,!0)>=t-1)break;t--}r++}return tt}(e)}function dt(e){var t,n=e._a;return n&&-2===g(e).overflow&&(t=n[_e]<0||11Pe(n[me],n[_e])?ye:n[ge]<0||24Ae(n,r,a)?g(e)._overflowWeeks=!0:null!=u?g(e)._overflowWeekday=!0:(o=Ee(n,s,i,r,a),e._a[me]=o.year,e._dayOfYear=o.dayOfYear)}(e),null!=e._dayOfYear&&(r=ct(e._a[me],s[me]),(e._dayOfYear>Se(r)||0===e._dayOfYear)&&(g(e)._overflowDayOfYear=!0),n=Ge(r,0,e._dayOfYear),e._a[_e]=n.getUTCMonth(),e._a[ye]=n.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=a[t]=s[t];for(;t<7;t++)e._a[t]=a[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[ge]&&0===e._a[ve]&&0===e._a[pe]&&0===e._a[we]&&(e._nextDay=!0,e._a[ge]=0),e._d=(e._useUTC?Ge:function(e,t,n,s,i,r,a){var o;return e<100&&0<=e?(o=new Date(e+400,t,n,s,i,r,a),isFinite(o.getFullYear())&&o.setFullYear(e)):o=new Date(e,t,n,s,i,r,a),o}).apply(null,a),i=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[ge]=24),e._w&&void 0!==e._w.d&&e._w.d!==i&&(g(e).weekdayMismatch=!0)}}var mt=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,_t=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,yt=/Z|[+-]\d\d(?::?\d\d)?/,gt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],vt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],pt=/^\/?Date\((\-?\d+)/i;function wt(e){var t,n,s,i,r,a,o=e._i,u=mt.exec(o)||_t.exec(o);if(u){for(g(e).iso=!0,t=0,n=gt.length;tn.valueOf():n.valueOf()this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},mn.isLocal=function(){return!!this.isValid()&&!this._isUTC},mn.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},mn.isUtc=Et,mn.isUTC=Et,mn.zoneAbbr=function(){return this._isUTC?"UTC":""},mn.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},mn.dates=n("dates accessor is deprecated. Use date instead.",un),mn.months=n("months accessor is deprecated. Use month instead",Ue),mn.years=n("years accessor is deprecated. Use year instead",Oe),mn.zone=n("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}),mn.isDSTShifted=n("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!l(this._isDSTShifted))return this._isDSTShifted;var e={};if(w(e,this),(e=Ot(e))._a){var t=e._isUTC?y(e._a):bt(e._a);this._isDSTShifted=this.isValid()&&0>16,e>>8&255,255&e,1]}if(r.match(fr)){5!==r.length&&9!==r.length||(r=r.substr(1)),4===r.length&&(r=(r=r.split(""))[0]+r[0]+r[1]+r[1]+r[2]+r[2]+r[3]+r[3]);var n=parseInt(r,16);return[n>>24&255,n>>16&255,n>>8&255,Math.round((255&n)/255*100)/100]}throw new Error("unknown hex color: "+r)},ur=o.type;A.prototype.hex=function(r){return tr(this._rgb,r)},_.hex=function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];return new(Function.prototype.bind.apply(A,[null].concat(r,["hex"])))},b.format.hex=or,b.autodetect.push({p:4,test:function(r){for(var e=[],n=arguments.length-1;0>16,r>>8&255,255&r,1];throw new Error("unknown num color: "+r)},xe=o.type;A.prototype.num=function(){return Me(this._rgb)},_.num=function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];return new(Function.prototype.bind.apply(A,[null].concat(r,["num"])))},b.format.num=_e,b.autodetect.push({p:5,test:function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];if(1===r.length&&"number"===xe(r[0])&&0<=r[0]&&r[0]<=16777215)return"num"}});var Ae=o.unpack,Ee=o.type,Pe=Math.round;A.prototype.rgb=function(r){return void 0===r&&(r=!0),!1===r?this._rgb.slice(0,3):this._rgb.slice(0,3).map(Pe)},A.prototype.rgba=function(n){return void 0===n&&(n=!0),this._rgb.slice(0,4).map(function(r,e){return e<3?!1===n?r:Pe(r):r})},_.rgb=function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];return new(Function.prototype.bind.apply(A,[null].concat(r,["rgb"])))},b.format.rgb=function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];var n=Ae(r,"rgba");return void 0===n[3]&&(n[3]=1),n},b.autodetect.push({p:3,test:function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];if(r=Ae(r,"rgba"),"array"===Ee(r)&&(3===r.length||4===r.length&&"number"==Ee(r[3])&&0<=r[3]&&r[3]<=1))return"rgb"}});var Fe=Math.log,Oe=function(r){var e,n,t,a=r/100;return t=a<66?(e=255,n=-155.25485562709179-.44596950469579133*(n=a-2)+104.49216199393888*Fe(n),a<20?0:.8274096064007395*(t=a-10)-254.76935184120902+115.67994401066147*Fe(t)):(e=351.97690566805693+.114206453784165*(e=a-55)-40.25366309332127*Fe(e),n=325.4494125711974+.07943456536662342*(n=a-50)-28.0852963507957*Fe(n),255),[e,n,t,1]},je=o.unpack,Ge=Math.round,qe=function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];for(var n,t=je(r,"rgb"),a=t[0],f=t[2],o=1e3,u=4e4;.4=f/a?u=n:o=n}return Ge(n)};A.prototype.temp=A.prototype.kelvin=A.prototype.temperature=function(){return qe(this._rgb)},_.temp=_.kelvin=_.temperature=function(){for(var r=[],e=arguments.length;e--;)r[e]=arguments[e];return new(Function.prototype.bind.apply(A,[null].concat(r,["temp"])))},b.format.temp=b.format.kelvin=b.format.temperature=Oe;var Le=o.type;A.prototype.alpha=function(r,e){return void 0===e&&(e=!1),void 0!==r&&"number"===Le(r)?e?(this._rgb[3]=r,this):new A([this._rgb[0],this._rgb[1],this._rgb[2],r],"rgb"):this._rgb[3]},A.prototype.clipped=function(){return this._rgb._clipped||!1},A.prototype.darken=function(r){void 0===r&&(r=1);var e=this.lab();return e[0]-=qr*r,new A(e,"lab").alpha(this.alpha(),!0)},A.prototype.brighten=function(r){return void 0===r&&(r=1),this.darken(-r)},A.prototype.darker=A.prototype.darken,A.prototype.brighter=A.prototype.brighten,A.prototype.get=function(r){var e=r.split("."),n=e[0],t=e[1],a=this[n]();if(t){var f=n.indexOf(t);if(-1=s[n];)n++;return n-1}(r)/(s.length-2):g!==p?(r-p)/(g-p):1;t=k(t),e||(t=w(t)),1!==y&&(t=nn(t,y)),t=d[0]+t*(1-d[0]-d[1]),t=Math.min(1,Math.max(0,t));var a=Math.floor(1e4*t);if(m&&v[a])n=v[a];else{if("array"===en(b))for(var f=0;f=u[e+1];)e++;var n=(r-u[e])/(u[e+1]-u[e]);return o[e]+n*(o[e+1]-o[e])})}}return l=[p,g],N},N.mode=function(r){return arguments.length?(u=r,f(),N):u},N.range=function(r,e){return a(r),N},N.out=function(r){return n=r,N},N.spread=function(r){return arguments.length?(e=r,N):e},N.correctLightness=function(r){return null==r&&(r=!0),t=r,f(),w=t?function(r){for(var e=M(0,!0).lab()[0],n=M(1,!0).lab()[0],t=nn.max&&(n.max=r),n.count+=1)}),n.domain=[n.min,n.max],n.limits=function(r,e){return Nn(n,r,e)},n},Nn=function(r,e,n){void 0===e&&(e="equal"),void 0===n&&(n=7),"array"==Y(r)&&(r=Mn(r));var t=r.min,a=r.max,f=r.values.sort(function(r,e){return r-e});if(1===n)return[t,a];var o=[];if("c"===e.substr(0,1)&&(o.push(t),o.push(a)),"e"===e.substr(0,1)){o.push(t);for(var u=1;u 0");var c=Math.LOG10E*mn(t),i=Math.LOG10E*mn(a);o.push(t);for(var l=1;la?c.indexOf("-"):-1,c=c.replace(/[\+|\-]/g,"")),b._.includes(c,"a")&&(e=c.match(/a(k|m|b|t)?/),e=e?e[1]:!1,b._.includes(c," a")&&(q=" "),c=c.replace(new RegExp(q+"a[kmbt]?"),""),g>=r&&!e||"t"===e?(q+=m.abbreviations.trillion,a/=r):r>g&&g>=s&&!e||"b"===e?(q+=m.abbreviations.billion,a/=s):s>g&&g>=t&&!e||"m"===e?(q+=m.abbreviations.million,a/=t):(t>g&&g>=u&&!e||"k"===e)&&(q+=m.abbreviations.thousand,a/=u)),b._.includes(c,"[.]")&&(o=!0,c=c.replace("[.]",".")),h=a.toString().split(".")[0],i=c.split(".")[1],k=c.indexOf(","),p=(c.split(".")[0].split(",")[0].match(/0/g)||[]).length,i?(b._.includes(i,"[")?(i=i.replace("]",""),i=i.split("["),v=b._.toFixed(a,i[0].length+i[1].length,d,i[1].length)):v=b._.toFixed(a,i.length,d),h=v.split(".")[0],v=b._.includes(v,".")?m.delimiters.decimal+v.split(".")[1]:"",o&&0===Number(v.slice(1))&&(v="")):h=b._.toFixed(a,0,d),q&&!e&&Number(h)>=1e3&&q!==m.abbreviations.trillion)switch(h=String(Number(h)/1e3),q){case m.abbreviations.thousand:q=m.abbreviations.million;break;case m.abbreviations.million:q=m.abbreviations.billion;break;case m.abbreviations.billion:q=m.abbreviations.trillion}if(b._.includes(h,"-")&&(h=h.slice(1),w=!0),h.length0;x--)h="0"+h;return k>-1&&(h=h.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+m.delimiters.thousands)),0===c.indexOf(".")&&(h=""),l=h+v+(q?q:""),n?l=(n&&w?"(":"")+l+(n&&w?")":""):j>=0?l=0===j?(w?"-":"+")+l:l+(w?"-":"+"):w&&(l="-"+l),l},stringToNumber:function(a){var b,c,d,e=f[h.currentLocale],g=a,i={thousand:3,million:6,billion:9,trillion:12};if(h.zeroFormat&&a===h.zeroFormat)c=0;else if(h.nullFormat&&a===h.nullFormat||!a.replace(/[^0-9]+/g,"").length)c=null;else{c=1,"."!==e.delimiters.decimal&&(a=a.replace(/\./g,"").replace(e.delimiters.decimal,"."));for(b in i)if(d=new RegExp("[^a-zA-Z]"+e.abbreviations[b]+"(?:\\)|(\\"+e.currency.symbol+")?(?:\\))?)?$"),g.match(d)){c*=Math.pow(10,i[b]);break}c*=(a.split("-").length+Math.min(a.split("(").length-1,a.split(")").length-1))%2?1:-1,a=a.replace(/[^0-9\.]+/g,""),c*=Number(a)}return c},isNaN:function(a){return"number"==typeof a&&isNaN(a)},includes:function(a,b){return-1!==a.indexOf(b)},insert:function(a,b,c){return a.slice(0,c)+b+a.slice(c)},reduce:function(a,b){if(null===this)throw new TypeError("Array.prototype.reduce called on null or undefined");if("function"!=typeof b)throw new TypeError(b+" is not a function");var c,d=Object(a),e=d.length>>>0,f=0;if(3===arguments.length)c=arguments[2];else{for(;e>f&&!(f in d);)f++;if(f>=e)throw new TypeError("Reduce of empty array with no initial value");c=d[f++]}for(;e>f;f++)f in d&&(c=b(c,d[f],f,d));return c},multiplier:function(a){var b=a.toString().split(".");return b.length<2?1:Math.pow(10,b[1].length)},correctionFactor:function(){var a=Array.prototype.slice.call(arguments);return a.reduce(function(a,b){var d=c.multiplier(b);return a>d?a:d},1)},toFixed:function(a,b,c,d){var e,f,g,h,i=a.toString().split("."),j=b-(d||0);return e=2===i.length?Math.min(Math.max(i[1].length,j),b):j,g=Math.pow(10,e),h=(c(a+"e+"+e)/g).toFixed(e),d>b-e&&(f=new RegExp("\\.?0{1,"+(d-(b-e))+"}$"),h=h.replace(f,"")),h}},b.options=h,b.formats=e,b.locales=f,b.locale=function(a){return a&&(h.currentLocale=a.toLowerCase()),h.currentLocale},b.localeData=function(a){if(!a)return f[h.currentLocale];if(a=a.toLowerCase(),!f[a])throw new Error("Unknown locale : "+a);return f[a]},b.reset=function(){for(var a in g)h[a]=g[a]},b.zeroFormat=function(a){h.zeroFormat="string"==typeof a?a:null},b.nullFormat=function(a){h.nullFormat="string"==typeof a?a:null},b.defaultFormat=function(a){h.defaultFormat="string"==typeof a?a:"0.0"},b.register=function(a,b,c){if(b=b.toLowerCase(),this[a+"s"][b])throw new TypeError(b+" "+a+" already registered.");return this[a+"s"][b]=c,c},b.validate=function(a,c){var d,e,f,g,h,i,j,k;if("string"!=typeof a&&(a+="",console.warn&&console.warn("Numeral.js: Value is not string. It has been co-erced to: ",a)),a=a.trim(),a.match(/^\d+$/))return!0;if(""===a)return!1;try{j=b.localeData(c)}catch(l){j=b.localeData(b.locale())}return f=j.currency.symbol,h=j.abbreviations,d=j.delimiters.decimal,e="."===j.delimiters.thousands?"\\.":j.delimiters.thousands,k=a.match(/^[^\d]+/),null!==k&&(a=a.substr(1),k[0]!==f)?!1:(k=a.match(/[^\d]+$/),null!==k&&(a=a.slice(0,-1),k[0]!==h.thousand&&k[0]!==h.million&&k[0]!==h.billion&&k[0]!==h.trillion)?!1:(i=new RegExp(e+"{2}"),a.match(/[^\d.,]/g)?!1:(g=a.split(d),g.length>2?!1:g.length<2?!!g[0].match(/^\d+.*\d$/)&&!g[0].match(i):1===g[0].length?!!g[0].match(/^\d+$/)&&!g[0].match(i)&&!!g[1].match(/^\d+$/):!!g[0].match(/^\d+.*\d$/)&&!g[0].match(i)&&!!g[1].match(/^\d+$/))))},b.fn=a.prototype={clone:function(){return b(this)},format:function(a,c){var d,f,g,i=this._value,j=a||h.defaultFormat;if(c=c||Math.round,0===i&&null!==h.zeroFormat)f=h.zeroFormat;else if(null===i&&null!==h.nullFormat)f=h.nullFormat;else{for(d in e)if(j.match(e[d].regexps.format)){g=e[d].format;break}g=g||b._.numberToFormat,f=g(i,j,c)}return f},value:function(){return this._value},input:function(){return this._input},set:function(a){return this._value=Number(a),this},add:function(a){function b(a,b,c,e){return a+Math.round(d*b)}var d=c.correctionFactor.call(null,this._value,a);return this._value=c.reduce([this._value,a],b,0)/d,this},subtract:function(a){function b(a,b,c,e){return a-Math.round(d*b)}var d=c.correctionFactor.call(null,this._value,a);return this._value=c.reduce([a],b,Math.round(this._value*d))/d,this},multiply:function(a){function b(a,b,d,e){var f=c.correctionFactor(a,b);return Math.round(a*f)*Math.round(b*f)/Math.round(f*f)}return this._value=c.reduce([this._value,a],b,1),this},divide:function(a){function b(a,b,d,e){var f=c.correctionFactor(a,b);return Math.round(a*f)/Math.round(b*f)}return this._value=c.reduce([this._value,a],b),this},difference:function(a){return Math.abs(b(this._value).subtract(a).value())}},b.register("locale","en",{delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(a){var b=a%10;return 1===~~(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th"},currency:{symbol:"$"}}),function(){b.register("format","bps",{regexps:{format:/(BPS)/,unformat:/(BPS)/},format:function(a,c,d){var e,f=b._.includes(c," BPS")?" ":"";return a=1e4*a,c=c.replace(/\s?BPS/,""),e=b._.numberToFormat(a,c,d),b._.includes(e,")")?(e=e.split(""),e.splice(-1,0,f+"BPS"),e=e.join("")):e=e+f+"BPS",e},unformat:function(a){return+(1e-4*b._.stringToNumber(a)).toFixed(15)}})}(),function(){var a={base:1e3,suffixes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]},c={base:1024,suffixes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},d=a.suffixes.concat(c.suffixes.filter(function(b){return a.suffixes.indexOf(b)<0})),e=d.join("|");e="("+e.replace("B","B(?!PS)")+")",b.register("format","bytes",{regexps:{format:/([0\s]i?b)/,unformat:new RegExp(e)},format:function(d,e,f){var g,h,i,j,k=b._.includes(e,"ib")?c:a,l=b._.includes(e," b")||b._.includes(e," ib")?" ":"";for(e=e.replace(/\s?i?b/,""),h=0;h<=k.suffixes.length;h++)if(i=Math.pow(k.base,h),j=Math.pow(k.base,h+1),null===d||0===d||d>=i&&j>d){l+=k.suffixes[h],i>0&&(d/=i);break}return g=b._.numberToFormat(d,e,f),g+l},unformat:function(d){var e,f,g=b._.stringToNumber(d);if(g){for(e=a.suffixes.length-1;e>=0;e--){if(b._.includes(d,a.suffixes[e])){f=Math.pow(a.base,e);break}if(b._.includes(d,c.suffixes[e])){f=Math.pow(c.base,e);break}}g*=f||1}return g}})}(),function(){b.register("format","currency",{regexps:{format:/(\$)/},format:function(a,c,d){var e,f,g,h=b.locales[b.options.currentLocale],i={before:c.match(/^([\+|\-|\(|\s|\$]*)/)[0],after:c.match(/([\+|\-|\)|\s|\$]*)$/)[0]};for(c=c.replace(/\s?\$\s?/,""),e=b._.numberToFormat(a,c,d),a>=0?(i.before=i.before.replace(/[\-\(]/,""),i.after=i.after.replace(/[\-\)]/,"")):0>a&&!b._.includes(i.before,"-")&&!b._.includes(i.before,"(")&&(i.before="-"+i.before),g=0;g=0;g--)switch(f=i.after[g]){case"$":e=g===i.after.length-1?e+h.currency.symbol:b._.insert(e,h.currency.symbol,-(i.after.length-(1+g)));break;case" ":e=g===i.after.length-1?e+" ":b._.insert(e," ",-(i.after.length-(1+g)+h.currency.symbol.length-1))}return e}})}(),function(){b.register("format","exponential",{regexps:{format:/(e\+|e-)/,unformat:/(e\+|e-)/},format:function(a,c,d){var e,f="number"!=typeof a||b._.isNaN(a)?"0e+0":a.toExponential(),g=f.split("e");return c=c.replace(/e[\+|\-]{1}0/,""),e=b._.numberToFormat(Number(g[0]),c,d),e+"e"+g[1]},unformat:function(a){function c(a,c,d,e){var f=b._.correctionFactor(a,c),g=a*f*(c*f)/(f*f);return g}var d=b._.includes(a,"e+")?a.split("e+"):a.split("e-"),e=Number(d[0]),f=Number(d[1]);return f=b._.includes(a,"e-")?f*=-1:f,b._.reduce([e,Math.pow(10,f)],c,1)}})}(),function(){b.register("format","ordinal",{regexps:{format:/(o)/},format:function(a,c,d){var e,f=b.locales[b.options.currentLocale],g=b._.includes(c," o")?" ":"";return c=c.replace(/\s?o/,""),g+=f.ordinal(a),e=b._.numberToFormat(a,c,d),e+g}})}(),function(){b.register("format","percentage",{regexps:{format:/(%)/,unformat:/(%)/},format:function(a,c,d){var e,f=b._.includes(c," %")?" ":"";return b.options.scalePercentBy100&&(a=100*a),c=c.replace(/\s?\%/,""),e=b._.numberToFormat(a,c,d),b._.includes(e,")")?(e=e.split(""),e.splice(-1,0,f+"%"),e=e.join("")):e=e+f+"%",e},unformat:function(a){var c=b._.stringToNumber(a);return b.options.scalePercentBy100?.01*c:c}})}(),function(){b.register("format","time",{regexps:{format:/(:)/,unformat:/(:)/},format:function(a,b,c){var d=Math.floor(a/60/60),e=Math.floor((a-60*d*60)/60),f=Math.round(a-60*d*60-60*e);return d+":"+(10>e?"0"+e:e)+":"+(10>f?"0"+f:f)},unformat:function(a){var b=a.split(":"),c=0;return 3===b.length?(c+=60*Number(b[0])*60,c+=60*Number(b[1]),c+=Number(b[2])):2===b.length&&(c+=60*Number(b[0]),c+=Number(b[1])),Number(c)}})}(),b}); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var dataform = function () { function dataform(options) { var _this = this; _classCallCheck(this, dataform); this.submit = function (options) { if (_this.options.path) { _this.submit_state = 'submitting'; _this.render(); var postOptions = { on_success: function on_success(ob) { if (ob.response && ob.response.valid == true) { _this.probs = false; if (_this.options.on_submit_complete) { _this.options.on_submit_complete({ response: ob.response }); } _this.submit_state = false; _this.submitted_count++; _this.render(); } else { // console.log(ob); _this.submit_state = false; if (ob.response && ob.response.probs) { _this.probs = ob.response.probs; if (_this.options.on_submit_fail) { _this.options.on_submit_fail({ response: ob.response }); } } _this.render(); } } }; if (_this.options.path_format) { postOptions.path_format = _this.options.path_format; } ui.controller.formPost(_this.options.path, _this.data, postOptions); } else { console.error('No form path.'); } }; this.render = function () { if (_this.context) { _this.context.setState({ version: Date.now() }); } }; this.options = options; this.data = this.options.data || {}; this.context = this.options.context || false; this.probs = false; this.submitted_count = 0; this.submit_state = false; } _createClass(dataform, [{ key: 'update', value: function update(updates) { for (var dataKey in updates) { if (updates.hasOwnProperty(dataKey)) { if (this.data[dataKey] != updates[dataKey]) { this.data[dataKey] = updates[dataKey]; delete this.probs[dataKey]; } } } this.render(); } }]); return dataform; }(); var Controls = function (_preact$Component) { _inherits(Controls, _preact$Component); function Controls() { _classCallCheck(this, Controls); var _this2 = _possibleConstructorReturn(this, (Controls.__proto__ || Object.getPrototypeOf(Controls)).call(this)); _this2.state = {}; return _this2; } _createClass(Controls, [{ key: 'componentDidMount', value: function componentDidMount() {} }, { key: 'componentWillUnmount', value: function componentWillUnmount() {} }, { key: 'render', value: function render() { var controls = []; if (this.props.items) { for (var itemKey in this.props.items) { if (this.props.items.hasOwnProperty(itemKey)) { var item = this.props.items[itemKey]; controls.push(e('div', { id: itemKey, class: 'controls-item' }, e(Button, item))); } } } return e('div', { class: 'controls' }, controls); } }]); return Controls; }(preact.Component); var Probs = function (_preact$Component2) { _inherits(Probs, _preact$Component2); function Probs() { _classCallCheck(this, Probs); var _this3 = _possibleConstructorReturn(this, (Probs.__proto__ || Object.getPrototypeOf(Probs)).call(this)); _this3.state = {}; return _this3; } _createClass(Probs, [{ key: 'componentDidMount', value: function componentDidMount() {} }, { key: 'componentWillUnmount', value: function componentWillUnmount() {} }, { key: 'render', value: function render() { var probs = []; if (this.props.items) { for (var itemKey in this.props.items) { if (this.props.items.hasOwnProperty(itemKey)) { var item = this.props.items[itemKey]; probs.push(e('div', { id: itemKey, class: 'probs-item f-s-12 c-white f-w-semi' }, this.props.items[itemKey])); } } } return e('div', { class: 'probs' }, probs); } }]); return Probs; }(preact.Component); var Button = function (_preact$Component3) { _inherits(Button, _preact$Component3); function Button() { _classCallCheck(this, Button); var _this4 = _possibleConstructorReturn(this, (Button.__proto__ || Object.getPrototypeOf(Button)).call(this)); _this4.click = function (event) { if (_this4.props.onClick) { event.preventDefault(); event.stopPropagation(); _this4.props.onClick({ event: event }); } }; _this4.state = {}; return _this4; } _createClass(Button, [{ key: 'componentDidMount', value: function componentDidMount() {} }, { key: 'componentWillUnmount', value: function componentWillUnmount() {} }, { key: 'render', value: function render() { var classes = ['button']; if (this.props.color) { classes.push(this.props.color); } return e('button', { type: 'button', onClick: this.click, class: classes.join(' ') }, this.props.title); } }]); return Button; }(preact.Component); var Form = function (_preact$Component4) { _inherits(Form, _preact$Component4); function Form() { _classCallCheck(this, Form); var _this5 = _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).call(this)); _this5.inputKeyUp = function (ob) { if (ob.event.keyCode === 13) { if (_this5.props.dataform && _this5.props.dataform.options.form_enter) { _this5.props.dataform.options.form_enter(ob); } else if (_this5.props.dataform) { ob.event.target.blur(); _this5.props.dataform.submit(); setTimeout(function () { ob.event.target.focus(); }, 20); } } else { return _this5.inputChange(ob); } }; _this5.inputChange = function (ob) { if (_this5.props.dataform) { if (ob.value) { _this5.props.dataform.update(_defineProperty({}, ob.field, ob.value)); } else if (ob.event) { _this5.props.dataform.update(_defineProperty({}, ob.field, ob.event.target.value)); } } }; _this5.state = {}; return _this5; } _createClass(Form, [{ key: 'componentDidMount', value: function componentDidMount() {} }, { key: 'componentWillUnmount', value: function componentWillUnmount() {} }, { key: 'render', value: function render() { var _this6 = this; var fields = []; var formClasses = ['form']; if (this.props.dataform && this.props.dataform.submit_state == 'submitting') { formClasses.push('submitting'); } if (this.props.dataform && this.props.dataform.submitted_count > 0) { formClasses.push('submitted'); } if (this.props.fields) { for (var fieldKey in this.props.fields) { if (this.props.fields.hasOwnProperty(fieldKey)) { var fieldClasses = ['field']; var field = this.props.fields[fieldKey]; var inputType = field.input_type || field.type || 'text'; var fieldClass = ''; var input = null; var label = null; var value = ''; if (this.props.data && this.props.data[fieldKey]) { value = this.props.data[fieldKey]; } else if (this.props.dataform && this.props.dataform.data && this.props.dataform.data[fieldKey]) { value = this.props.dataform.data[fieldKey]; } if (field.input_type == 'togglebuttons') { if (!Array.isArray(value)) { value = []; } } var placeholder = null; if (field.placeholder) placeholder = field.placeholder; if (this.props.placeholder) { placeholder = field.title; } if (!this.props.placeholder) { label = e('div', { class: 'field-label f-s-14 f-uppercase c-white quantico' }, field.title); } var prob = null; if (this.props.dataform && this.props.dataform.probs && this.props.dataform.probs[fieldKey]) { prob = e('div', { class: 'field-prob' }, this.props.dataform.probs[fieldKey]); } if (this.props.hasOwnProperty('is_current') && this.props.is_current == false) { input = e('div', { class: 'field-not-current' }, value); } else if (field.type == 'checkboxes') { input = []; fieldClass = 'checkboxes'; var fieldOptions = field.options.split('\n'); var _loop = function _loop() { var fieldOption = fieldOptions[i]; input.push(e('label', { key: i, class: 'checkboxes-checkbox' }, e('div', { class: 'checkboxes-checkbox-box' }, e('input', { type: 'checkbox', onChange: function onChange(event) { var curVal = _this6.props.dataform.data[fieldKey]; var curValParts = void 0; if (curVal) { curValParts = curVal.split('\n'); } else { curValParts = []; } var newVal = []; for (var j = 0; j < curValParts.length; j++) { curValParts[j]; if (curValParts[j] != fieldOption) { newVal.push(curValParts[j]); } } if (event.target.checked) { newVal.push(fieldOption); } console.log(newVal); _this6.props.dataform.update(_defineProperty({}, fieldKey, newVal.join('\n'))); }, value: fieldOption })), e('div', { class: 'checkboxes-checkbox-title' }, fieldOption))); }; for (var i = 0; i < fieldOptions.length; i++) { _loop(); } } else { fieldClass = 'text'; var inputTag = 'input'; if (inputType == 'description') { inputTag = 'textarea'; } input = e(inputTag, { // onChange: event => { // this.inputChange({ // event, // field: fieldKey // }); // }, tabIndex: 1, placeholder: placeholder, onKeyUp: function (fieldKey, event) { this.inputKeyUp({ event: event, field: fieldKey }); }.bind(this, fieldKey), type: inputType, value: value }); } fields.push(e('div', { class: fieldClasses.join(' ') }, label, e('div', { class: 'field-input ' + fieldClass }, input), prob)); } } } return e('div', { class: formClasses.join(' ') }, fields); } }]); return Form; }(preact.Component); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Viewer = function (_preact$Component) { _inherits(Viewer, _preact$Component); function Viewer() { _classCallCheck(this, Viewer); var _this = _possibleConstructorReturn(this, (Viewer.__proto__ || Object.getPrototypeOf(Viewer)).call(this)); _this.clear = function () { ui.hash.clear(); }; _this.state = {}; return _this; } _createClass(Viewer, [{ key: 'componentDidMount', value: function componentDidMount() {} }, { key: 'componentWillUnmount', value: function componentWillUnmount() {} }, { key: 'render', value: function render() { var controls = []; var content = null; if (this.props.type == 'image') { var imageStyle = { backgroundImage: ui.cdn.imageUrl(this.props.image.file, { maxD: 3000 }, 'bg_val') }; if (this.props.image.focus && this.props.image.focus.x) { imageStyle.backgroundPosition = this.props.image.focus.x + '% ' + this.props.image.focus.y + '% '; } else { imageStyle.backgroundSize = 'contain'; imageStyle.backgroundRepeat = 'no-repeat'; } content = e('div', { style: imageStyle, class: 'viewer-content-image' }, ''); console.log('this one here'); } if (this.props.type == 'iframe') { content = e('div', { class: 'viewer-content-iframe' }, e('iframe', { onLoad: function onLoad() { console.log('LOADED!'); }, class: 'viewer-content-iframe-frame', src: this.props.url, frameborder: 0 })); } if (this.props.type == 'youtube') { var parsedUrl = new URL(this.props.youtube); var video = parsedUrl.searchParams.get("v"); content = e('div', { class: 'viewer-content-youtube' }, e('iframe', { class: 'viewer-content-youtube-frame', src: 'https://www.youtube.com/embed/' + video, frameborder: 0, allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture', allowfullscreen: true })); } if (this.props.type == 'modal') { content = e('div', {}, 'Modal'); } return e('div', { onClick: this.clear, class: 'viewer' }, e('div', { onClick: function onClick(event) { event.preventDefault(); event.stopPropagation(); }, class: 'viewer-box' }, e('div', { class: 'viewer-box-head' }, e('div', { class: 'viewer-box-head-title' }, this.props.title), e('div', { class: 'viewer-box-head-tools' }, e('div', { onClick: this.clear, class: 'viewer-box-head-tools-tool' }, e('svg', { viewBox: '0 0 100 75' }, e('use', { 'xlink:href': '/web/amplib/df/util/sprite.svg#x' }))))), e('div', { class: 'viewer-box-content' }, content))); } }]); return Viewer; }(preact.Component); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Modal = function (_preact$Component) { _inherits(Modal, _preact$Component); function Modal() { _classCallCheck(this, Modal); var _this = _possibleConstructorReturn(this, (Modal.__proto__ || Object.getPrototypeOf(Modal)).call(this)); _this.close = function () { console.log('close'); _this.props.close(); }; _this.state = {}; return _this; } _createClass(Modal, [{ key: 'componentDidMount', value: function componentDidMount() {} }, { key: 'componentWillUnmount', value: function componentWillUnmount() {} }, { key: 'render', value: function render() { var controls = []; var content = this.props.render(); return e('div', { onClick: this.close, class: 'modal' }, e('div', { onClick: function onClick(event) { event.preventDefault(); event.stopPropagation(); }, class: 'modal-box' }, e('div', { class: 'modal-box-head' }, e('div', { class: 'modal-box-head-title f-s-18 c-primary f-w-semi quantico' }, this.props.title), e('div', { class: 'modal-box-head-tools' }, e('div', { onClick: this.close, class: 'modal-box-head-tools-tool' }, e('svg', { viewBox: '0 0 100 75' }, e('use', { 'xlink:href': '/web/amplib/df/util/sprite.svg#x' }))))), e('div', { class: 'modal-box-content' }, content))); } }]); return Modal; }(preact.Component); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Ui_controller = function Ui_controller(ui) { var _this = this; _classCallCheck(this, Ui_controller); this.model = function (path, data, cb) { var url = _this.appUrl('controller/model/' + path + '.htp', false, {}); fetch(url, { method: 'GET', // or 'PUT' headers: { 'Content-Type': 'text/plain' } }).then(function (response) { return response.json(); }).then(function (data) { if (cb) { cb(data); } }).catch(function (error) { if (cb) { cb(error); } }); }; this.formPost = function (path, data, options) { options = options || {}; var pathFormat = options.path_format || 'form_view'; var url = void 0; if (pathFormat == 'direct') { url = _this.appUrl(path, false, { direct: true }); } else { url = _this.appUrl('controller/' + pathFormat + '/' + path + '.htp', { recupdate_action: 'update' }); } fetch(url, { method: 'POST', // or 'PUT' headers: { 'Content-Type': 'text/plain' }, body: JSON.stringify({ data: data }) }).then(function (response) { return response.json(); }).then(function (data) { if (options.on_success) { options.on_success({ response: data }); } }).catch(function (error) { if (options.on_error) { options.on_error({ response: data }); } }); }; this.appUrl = function (path, addParams, options) { var url = []; var qs = []; options = options || {}; if (!options.direct) { url.push(_this.ui.options.app_url_root); } url.push(path); var params = { // s: this.ui.options.site, // p: this.ui.options.page, uslapp_site: _this.ui.options.site, uslapp_page: _this.ui.options.page, ul_client_date: new Date().toISOString(), ul_client_key: _this.ui.options.ul_client_key, ul_app_id: _this.ui.options.app, uslapp_session: _this.ui.options.uslapp_session, ul_client_tab: _this.ui.tab }; if (addParams) { for (var paramKey in addParams) { if (addParams.hasOwnProperty(paramKey)) { params[paramKey] = addParams[paramKey]; } } } for (var paramKey in params) { if (params.hasOwnProperty(paramKey)) { qs.push(paramKey + '=' + encodeURIComponent(params[paramKey])); } } if (path.indexOf('?') !== -1) { url.push('&' + qs.join('&')); } else { url.push('?' + qs.join('&')); } return url.join(''); }; this.ui = ui; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Ui_dom = function Ui_dom(ui) { var _this = this; _classCallCheck(this, Ui_dom); this.ini = function () { _this.iniResize(); _this.iniScroll(); _this.iniFeatures(); _this.iniIntersect(); }; this.sslCheck = function () { if (location.protocol != 'https:') { location.href = 'https:' + window.location.href.substring(window.location.protocol.length); } }; this.uid = function () { return _this.uidcur++; }; this.checkAll = function () { _this.checkScroll(); _this.checkMobile(); }; this.iniIntersect = function () { var options = { root: document.querySelector('#scrollArea'), rootMargin: '0px', threshold: .4 }; _this.observer = new IntersectionObserver(_this.intersectCallback, options); }; this.backgroundToImge = function (backgroundSelector, imageSelector) { var bg = document.querySelector(backgroundSelector); var img = document.querySelector(imageSelector); var style = bg.currentStyle || window.getComputedStyle(bg, false); var bi = style.backgroundImage.slice(4, -1).replace(/"/g, ""); img.src = bi; console.log(bi); }; this.intersectCallback = function (entries, observer) { // console.log(entries); entries.forEach(function (entry) { // console.log(entry); if (entry.isIntersecting) { entry.target.classList.remove('ui-dom-intersect-below'); entry.target.classList.remove('ui-dom-intersect-above'); entry.target.classList.add('ui-dom-intersect-in'); entry.target.classList.remove('ui-dom-intersect-out'); } else { var windowHeightHalf = window.outerHeight / 2; if (entry.boundingClientRect.bottom > windowHeightHalf) { entry.target.classList.add('ui-dom-intersect-below'); entry.target.classList.remove('ui-dom-intersect-above'); } else { entry.target.classList.remove('ui-dom-intersect-below'); entry.target.classList.add('ui-dom-intersect-above'); } entry.target.classList.remove('ui-dom-intersect-in'); entry.target.classList.add('ui-dom-intersect-out'); } // Each entry describes an intersection change for one observed // target element: // entry.boundingClientRect // entry.intersectionRatio // entry.intersectionRect // entry.isIntersecting // entry.rootBounds // entry.target // entry.time }); }; this.iniScroll = function () { _this.checkScrollLastTop = 0; window.addEventListener('scroll', _this.checkScroll); }; this.iniResize = function () { window.addEventListener('resize', _this.checkAll); }; this.iniFeatures = function () { _this.featureWebP(); }; this.iOS = function () { return ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) // iPad on iOS 13 detection || navigator.userAgent.includes("Mac") && "ontouchend" in document; }; this.featureWebP = function () { var webP = false; var elem = document.createElement('canvas'); if (!!(elem.getContext && elem.getContext('2d'))) { webP = elem.toDataURL('image/webp').indexOf('data:image/webp') == 0; } if (webP) { document.documentElement.classList.add('f-webp'); _this.sup.webp = true; } else { document.documentElement.classList.add('f-webp-0'); _this.sup.webp = false; } }; this.checkScroll = function () { var top = (window.pageYOffset || document.scrollTop) - (document.clientTop || 0); var scrollDiff = top - _this.checkScrollLastTop; // console.log(scrollDiff); if (top > _this.checkScrollLastTop) { document.body.classList.add('scrolling-last-down'); document.body.classList.remove('scrolling-last-up'); } else if (top < _this.checkScrollLastTop) { document.body.classList.remove('scrolling-last-down'); document.body.classList.add('scrolling-last-up'); } _this.checkScrollLastTop = top; if (top >= 10) { document.body.classList.add('scrolled-down'); document.body.classList.remove('scrolled-up'); } else { document.body.classList.remove('scrolled-down'); document.body.classList.add('scrolled-up'); } }; this.checkMobile = function () { // console.log(document.body.clientWidth); if (document.body.clientWidth > 800) { _this.screen = 'desktop'; document.body.classList.add('desktop'); document.body.classList.remove('mobile'); } else { _this.screen = 'mobile'; document.body.classList.remove('desktop'); document.body.classList.add('mobile'); } console.log(_this.screen, 'changed'); }; this.ui = ui; this.screen = false; this.sup = { webp: false }; this.checkAll(); this.ini(); this.uidcur = 1; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Ui_cdn = function () { function Ui_cdn(ui) { var _this = this; _classCallCheck(this, Ui_cdn); this.imageUrl = function (path, options, format, config) { var optionList = []; config = config || {}; if (format) { if (_this.isObject(format)) { config = format; format = false; } } // console.log(config); if (options) { for (var optionId in options) { optionList.push(optionId + '_' + options[optionId]); } } var suffix = ''; optionList.push('tkn_3ds99udi4hffwei39d0gtidsjqewr'); var optionsString = optionList.join('|'); if (options) { if (options.direct_download) { optionsString = 'df'; } if (options.df) { optionsString = 'df'; } if (options.info) { optionsString = 'df'; suffix = '.info'; } } if (config.local) { path = '/cdn_image/' + optionsString + '/' + path + suffix; } else { path = '//d2beia7gtp5yjy.cloudfront.net/cdn_image/' + optionsString + '/' + path + suffix; } // console.log(path); if (format) { if (format == 'css_bg_val') { return "url('" + path + "');"; } if (format == 'bg_val') { return "url('" + path + "')"; } } return path; }; this.ui = ui; } _createClass(Ui_cdn, [{ key: 'isObject', value: function isObject(obj) { return obj === Object(obj); } }]); return Ui_cdn; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Ui_hash = function Ui_hash(ui) { var _this = this; _classCallCheck(this, Ui_hash); this.clear = function () { window.location.hash = ''; }; this.change = function () { _this.hash = window.location.hash.substr(1); for (var bindName in _this.bound) { if (_this.bound.hasOwnProperty(bindName)) { _this.bound[bindName].callback({ hash: _this.hash }); } } }; this.bind = function (name, callback) { _this.bound[name] = { callback: callback }; }; this.ui = ui; this.bound = {}; window.addEventListener('hashchange', this.change, false); }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Ui_layout = function () { function Ui_layout(ui) { _classCallCheck(this, Ui_layout); this.ui = ui; } _createClass(Ui_layout, [{ key: "autoMatrix", value: function autoMatrix(options) { var width = options.width, height = options.height, items = options.items, padding = options.padding; var itemsUse = items.slice(0); var count = itemsUse.length; var grid = { x: 0, y: 0 }; while (grid.x * grid.y < count) { if (width > height) { if (count == 3) { grid.x = 2; grid.y = 1; } grid.x++; if (grid.x * grid.y >= count) break; grid.y++; if (grid.x * grid.y >= count) break; } else { grid.y++; if (grid.x * grid.y >= count) break; grid.x++; if (grid.x * grid.y >= count) break; } } var remainder = grid.x * grid.y - count; var remainderWas = remainder; // console.log(grid); // console.log(remainder); var matrix = { rows: [] }; for (var y = 0; y < grid.y; y++) { var xUse = grid.x; if (remainderWas >= grid.y - y) { if (remainder > 0) { xUse--; remainder--; } } // console.log('xUse', xUse); var newRow = { items: [] }; for (var x = 0; x < xUse; x++) { newRow.items.push(itemsUse.shift()); } matrix.rows.push(newRow); } var itemHeight = (height - padding * (matrix.rows.length + 1)) / matrix.rows.length; var itemWidth = (width - padding * (grid.x + 1)) / grid.x; matrix.rows = matrix.rows.map(function (row, rowKey) { var rowItemSpace = { width: itemWidth, height: itemHeight }; var rowExtraSpace = 0; if (grid.x > row.items.length) { var rowXDiff = grid.x - row.items.length; rowExtraSpace = rowXDiff * (itemWidth + padding) * .5; } row.items = row.items.map(function (item, itemKey) { var itemBox = { width: rowItemSpace.width, height: rowItemSpace.height }; itemBox.left = rowExtraSpace + itemWidth * itemKey + padding * (itemKey + 1); itemBox.top = itemHeight * rowKey + padding * (rowKey + 1); item.box = itemBox; return item; }); return row; }); // console.log(matrix); return matrix; } }]); return Ui_layout; }(); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Ui_color = function () { _createClass(Ui_color, [{ key: 'hexToComplimentary', value: function hexToComplimentary(hex) { // Convert hex to rgb // Credit to Denis http://stackoverflow.com/a/36253499/4939630 var rgb = 'rgb(' + (hex = hex.replace('#', '')).match(new RegExp('(.{' + hex.length / 3 + '})', 'g')).map(function (l) { return parseInt(hex.length % 2 ? l + l : l, 16); }).join(',') + ')'; // Get array of RGB values rgb = rgb.replace(/[^\d,]/g, '').split(','); var r = rgb[0], g = rgb[1], b = rgb[2]; // Convert RGB to HSL // Adapted from answer by 0x000f http://stackoverflow.com/a/34946092/4939630 r /= 255.0; g /= 255.0; b /= 255.0; var max = Math.max(r, g, b); var min = Math.min(r, g, b); var h, s, l = (max + min) / 2.0; if (max == min) { h = s = 0; //achromatic } else { var d = max - min; s = l > 0.5 ? d / (2.0 - max - min) : d / (max + min); if (max == r && g >= b) { h = 1.0472 * (g - b) / d; } else if (max == r && g < b) { h = 1.0472 * (g - b) / d + 6.2832; } else if (max == g) { h = 1.0472 * (b - r) / d + 2.0944; } else if (max == b) { h = 1.0472 * (r - g) / d + 4.1888; } } h = h / 6.2832 * 360.0 + 0; // Shift hue to opposite side of wheel and convert to [0-1] value h += 180; if (h > 360) { h -= 360; } h /= 360; // Convert h s and l values into r g and b values // Adapted from answer by Mohsen http://stackoverflow.com/a/9493060/4939630 if (s === 0) { r = g = b = l; // achromatic } else { var hue2rgb = function hue2rgb(p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; var q = l < 0.5 ? l * (1 + s) : l + s - l * s; var p = 2 * l - q; r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); } r = Math.round(r * 255); g = Math.round(g * 255); b = Math.round(b * 255); // Convert r b and g values to hex rgb = b | g << 8 | r << 16; return "#" + (0x1000000 | rgb).toString(16).substring(1); } }]); function Ui_color(ui) { _classCallCheck(this, Ui_color); this.ui = ui; } return Ui_color; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Ui = function Ui(options) { _classCallCheck(this, Ui); // console.log(options); this.options = options; this.tab = Math.floor(Date.now() / 1000); this.controller = Ui_controller ? new Ui_controller(this) : false; this.dom = Ui_dom ? new Ui_dom(this) : false; this.layout = Ui_layout ? new Ui_layout(this) : false; this.color = Ui_color ? new Ui_color(this) : false; this.hash = Ui_hash ? new Ui_hash(this) : false; this.cdn = Ui_cdn ? new Ui_cdn(this) : false; }; // ui = new Ui({ // app_url_root: 'https://dev.userlite.com/apps/userlitestoreapps/sellerznext/v999/' // }); function Component(options) { var _this = this; this.options = options; this.id = options.id; this.data = options.data || {}; this.root = document.getElementById('component_' + this.id); this.state = options.state || {}; this.element = new window[options.component](this); this.setState = function (state, callback) { Object.assign(_this.state, state); _this.render(callback); }; this.before = function () { if (_this.element.before) { _this.element.before(); } }; this.render = function (callback) { if (_this.element.render) { _this.element.render(); } if (callback) { callback(); } }; this.before(); this.render(); } var backButton = document.getElementById('back'); if (backButton) { backButton.addEventListener('click', function (e) { e.preventDefault(); window.history.back(); }); } var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; (function (factory) { if (typeof define === "function" && define.amd) { // AMD. Register as an anonymous module. define([], factory); } else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object") { // Node/CommonJS module.exports = factory(); } else { // Browser globals window.noUiSlider = factory(); } })(function () { "use strict"; var VERSION = "14.6.4"; // var VERSION = "%%REPLACE_THIS_WITH_VERSION%%"; //region Helper Methods function isValidFormatter(entry) { return (typeof entry === "undefined" ? "undefined" : _typeof(entry)) === "object" && typeof entry.to === "function" && typeof entry.from === "function"; } function removeElement(el) { el.parentElement.removeChild(el); } function isSet(value) { return value !== null && value !== undefined; } // Bindable version function preventDefault(e) { e.preventDefault(); } // Removes duplicates from an array. function unique(array) { return array.filter(function (a) { return !this[a] ? this[a] = true : false; }, {}); } // Round a value to the closest 'to'. function closest(value, to) { return Math.round(value / to) * to; } // Current position of an element relative to the document. function offset(elem, orientation) { var rect = elem.getBoundingClientRect(); var doc = elem.ownerDocument; var docElem = doc.documentElement; var pageOffset = getPageOffset(doc); // getBoundingClientRect contains left scroll in Chrome on Android. // I haven't found a feature detection that proves this. Worst case // scenario on mis-match: the 'tap' feature on horizontal sliders breaks. if (/webkit.*Chrome.*Mobile/i.test(navigator.userAgent)) { pageOffset.x = 0; } return orientation ? rect.top + pageOffset.y - docElem.clientTop : rect.left + pageOffset.x - docElem.clientLeft; } // Checks whether a value is numerical. function isNumeric(a) { return typeof a === "number" && !isNaN(a) && isFinite(a); } // Sets a class and removes it after [duration] ms. function addClassFor(element, className, duration) { if (duration > 0) { addClass(element, className); setTimeout(function () { removeClass(element, className); }, duration); } } // Limits a value to 0 - 100 function limit(a) { return Math.max(Math.min(a, 100), 0); } // Wraps a variable as an array, if it isn't one yet. // Note that an input array is returned by reference! function asArray(a) { return Array.isArray(a) ? a : [a]; } // Counts decimals function countDecimals(numStr) { numStr = String(numStr); var pieces = numStr.split("."); return pieces.length > 1 ? pieces[1].length : 0; } // http://youmightnotneedjquery.com/#add_class function addClass(el, className) { if (el.classList && !/\s/.test(className)) { el.classList.add(className); } else { el.className += " " + className; } } // http://youmightnotneedjquery.com/#remove_class function removeClass(el, className) { if (el.classList && !/\s/.test(className)) { el.classList.remove(className); } else { el.className = el.className.replace(new RegExp("(^|\\b)" + className.split(" ").join("|") + "(\\b|$)", "gi"), " "); } } // https://plainjs.com/javascript/attributes/adding-removing-and-testing-for-classes-9/ function hasClass(el, className) { return el.classList ? el.classList.contains(className) : new RegExp("\\b" + className + "\\b").test(el.className); } // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes function getPageOffset(doc) { var supportPageOffset = window.pageXOffset !== undefined; var isCSS1Compat = (doc.compatMode || "") === "CSS1Compat"; var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? doc.documentElement.scrollLeft : doc.body.scrollLeft; var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? doc.documentElement.scrollTop : doc.body.scrollTop; return { x: x, y: y }; } // we provide a function to compute constants instead // of accessing window.* as soon as the module needs it // so that we do not compute anything if not needed function getActions() { // Determine the events to bind. IE11 implements pointerEvents without // a prefix, which breaks compatibility with the IE10 implementation. return window.navigator.pointerEnabled ? { start: "pointerdown", move: "pointermove", end: "pointerup" } : window.navigator.msPointerEnabled ? { start: "MSPointerDown", move: "MSPointerMove", end: "MSPointerUp" } : { start: "mousedown touchstart", move: "mousemove touchmove", end: "mouseup touchend" }; } // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md // Issue #785 function getSupportsPassive() { var supportsPassive = false; /* eslint-disable */ try { var opts = Object.defineProperty({}, "passive", { get: function get() { supportsPassive = true; } }); window.addEventListener("test", null, opts); } catch (e) {} /* eslint-enable */ return supportsPassive; } function getSupportsTouchActionNone() { return window.CSS && CSS.supports && CSS.supports("touch-action", "none"); } //endregion //region Range Calculation // Determine the size of a sub-range in relation to a full range. function subRangeRatio(pa, pb) { return 100 / (pb - pa); } // (percentage) How many percent is this value of this range? function fromPercentage(range, value, startRange) { return value * 100 / (range[startRange + 1] - range[startRange]); } // (percentage) Where is this value on this range? function toPercentage(range, value) { return fromPercentage(range, range[0] < 0 ? value + Math.abs(range[0]) : value - range[0], 0); } // (value) How much is this percentage on this range? function isPercentage(range, value) { return value * (range[1] - range[0]) / 100 + range[0]; } function getJ(value, arr) { var j = 1; while (value >= arr[j]) { j += 1; } return j; } // (percentage) Input a value, find where, on a scale of 0-100, it applies. function toStepping(xVal, xPct, value) { if (value >= xVal.slice(-1)[0]) { return 100; } var j = getJ(value, xVal); var va = xVal[j - 1]; var vb = xVal[j]; var pa = xPct[j - 1]; var pb = xPct[j]; return pa + toPercentage([va, vb], value) / subRangeRatio(pa, pb); } // (value) Input a percentage, find where it is on the specified range. function fromStepping(xVal, xPct, value) { // There is no range group that fits 100 if (value >= 100) { return xVal.slice(-1)[0]; } var j = getJ(value, xPct); var va = xVal[j - 1]; var vb = xVal[j]; var pa = xPct[j - 1]; var pb = xPct[j]; return isPercentage([va, vb], (value - pa) * subRangeRatio(pa, pb)); } // (percentage) Get the step that applies at a certain value. function getStep(xPct, xSteps, snap, value) { if (value === 100) { return value; } var j = getJ(value, xPct); var a = xPct[j - 1]; var b = xPct[j]; // If 'snap' is set, steps are used as fixed points on the slider. if (snap) { // Find the closest position, a or b. if (value - a > (b - a) / 2) { return b; } return a; } if (!xSteps[j - 1]) { return value; } return xPct[j - 1] + closest(value - xPct[j - 1], xSteps[j - 1]); } function handleEntryPoint(index, value, that) { var percentage; // Wrap numerical input in an array. if (typeof value === "number") { value = [value]; } // Reject any invalid input, by testing whether value is an array. if (!Array.isArray(value)) { throw new Error("noUiSlider (" + VERSION + "): 'range' contains invalid value."); } // Covert min/max syntax to 0 and 100. if (index === "min") { percentage = 0; } else if (index === "max") { percentage = 100; } else { percentage = parseFloat(index); } // Check for correct input. if (!isNumeric(percentage) || !isNumeric(value[0])) { throw new Error("noUiSlider (" + VERSION + "): 'range' value isn't numeric."); } // Store values. that.xPct.push(percentage); that.xVal.push(value[0]); // NaN will evaluate to false too, but to keep // logging clear, set step explicitly. Make sure // not to override the 'step' setting with false. if (!percentage) { if (!isNaN(value[1])) { that.xSteps[0] = value[1]; } } else { that.xSteps.push(isNaN(value[1]) ? false : value[1]); } that.xHighestCompleteStep.push(0); } function handleStepPoint(i, n, that) { // Ignore 'false' stepping. if (!n) { return; } // Step over zero-length ranges (#948); if (that.xVal[i] === that.xVal[i + 1]) { that.xSteps[i] = that.xHighestCompleteStep[i] = that.xVal[i]; return; } // Factor to range ratio that.xSteps[i] = fromPercentage([that.xVal[i], that.xVal[i + 1]], n, 0) / subRangeRatio(that.xPct[i], that.xPct[i + 1]); var totalSteps = (that.xVal[i + 1] - that.xVal[i]) / that.xNumSteps[i]; var highestStep = Math.ceil(Number(totalSteps.toFixed(3)) - 1); var step = that.xVal[i] + that.xNumSteps[i] * highestStep; that.xHighestCompleteStep[i] = step; } //endregion //region Spectrum function Spectrum(entry, snap, singleStep) { this.xPct = []; this.xVal = []; this.xSteps = [singleStep || false]; this.xNumSteps = [false]; this.xHighestCompleteStep = []; this.snap = snap; var index; var ordered = []; // [0, 'min'], [1, '50%'], [2, 'max'] // Map the object keys to an array. for (index in entry) { if (entry.hasOwnProperty(index)) { ordered.push([entry[index], index]); } } // Sort all entries by value (numeric sort). if (ordered.length && _typeof(ordered[0][0]) === "object") { ordered.sort(function (a, b) { return a[0][0] - b[0][0]; }); } else { ordered.sort(function (a, b) { return a[0] - b[0]; }); } // Convert all entries to subranges. for (index = 0; index < ordered.length; index++) { handleEntryPoint(ordered[index][1], ordered[index][0], this); } // Store the actual step values. // xSteps is sorted in the same order as xPct and xVal. this.xNumSteps = this.xSteps.slice(0); // Convert all numeric steps to the percentage of the subrange they represent. for (index = 0; index < this.xNumSteps.length; index++) { handleStepPoint(index, this.xNumSteps[index], this); } } Spectrum.prototype.getDistance = function (value) { var index; var distances = []; for (index = 0; index < this.xNumSteps.length - 1; index++) { // last "range" can't contain step size as it is purely an endpoint. var step = this.xNumSteps[index]; if (step && value / step % 1 !== 0) { throw new Error("noUiSlider (" + VERSION + "): 'limit', 'margin' and 'padding' of " + this.xPct[index] + "% range must be divisible by step."); } // Calculate percentual distance in current range of limit, margin or padding distances[index] = fromPercentage(this.xVal, value, index); } return distances; }; // Calculate the percentual distance over the whole scale of ranges. // direction: 0 = backwards / 1 = forwards Spectrum.prototype.getAbsoluteDistance = function (value, distances, direction) { var xPct_index = 0; // Calculate range where to start calculation if (value < this.xPct[this.xPct.length - 1]) { while (value > this.xPct[xPct_index + 1]) { xPct_index++; } } else if (value === this.xPct[this.xPct.length - 1]) { xPct_index = this.xPct.length - 2; } // If looking backwards and the value is exactly at a range separator then look one range further if (!direction && value === this.xPct[xPct_index + 1]) { xPct_index++; } var start_factor; var rest_factor = 1; var rest_rel_distance = distances[xPct_index]; var range_pct = 0; var rel_range_distance = 0; var abs_distance_counter = 0; var range_counter = 0; // Calculate what part of the start range the value is if (direction) { start_factor = (value - this.xPct[xPct_index]) / (this.xPct[xPct_index + 1] - this.xPct[xPct_index]); } else { start_factor = (this.xPct[xPct_index + 1] - value) / (this.xPct[xPct_index + 1] - this.xPct[xPct_index]); } // Do until the complete distance across ranges is calculated while (rest_rel_distance > 0) { // Calculate the percentage of total range range_pct = this.xPct[xPct_index + 1 + range_counter] - this.xPct[xPct_index + range_counter]; // Detect if the margin, padding or limit is larger then the current range and calculate if (distances[xPct_index + range_counter] * rest_factor + 100 - start_factor * 100 > 100) { // If larger then take the percentual distance of the whole range rel_range_distance = range_pct * start_factor; // Rest factor of relative percentual distance still to be calculated rest_factor = (rest_rel_distance - 100 * start_factor) / distances[xPct_index + range_counter]; // Set start factor to 1 as for next range it does not apply. start_factor = 1; } else { // If smaller or equal then take the percentual distance of the calculate percentual part of that range rel_range_distance = distances[xPct_index + range_counter] * range_pct / 100 * rest_factor; // No rest left as the rest fits in current range rest_factor = 0; } if (direction) { abs_distance_counter = abs_distance_counter - rel_range_distance; // Limit range to first range when distance becomes outside of minimum range if (this.xPct.length + range_counter >= 1) { range_counter--; } } else { abs_distance_counter = abs_distance_counter + rel_range_distance; // Limit range to last range when distance becomes outside of maximum range if (this.xPct.length - range_counter >= 1) { range_counter++; } } // Rest of relative percentual distance still to be calculated rest_rel_distance = distances[xPct_index + range_counter] * rest_factor; } return value + abs_distance_counter; }; Spectrum.prototype.toStepping = function (value) { value = toStepping(this.xVal, this.xPct, value); return value; }; Spectrum.prototype.fromStepping = function (value) { return fromStepping(this.xVal, this.xPct, value); }; Spectrum.prototype.getStep = function (value) { value = getStep(this.xPct, this.xSteps, this.snap, value); return value; }; Spectrum.prototype.getDefaultStep = function (value, isDown, size) { var j = getJ(value, this.xPct); // When at the top or stepping down, look at the previous sub-range if (value === 100 || isDown && value === this.xPct[j - 1]) { j = Math.max(j - 1, 1); } return (this.xVal[j] - this.xVal[j - 1]) / size; }; Spectrum.prototype.getNearbySteps = function (value) { var j = getJ(value, this.xPct); return { stepBefore: { startValue: this.xVal[j - 2], step: this.xNumSteps[j - 2], highestStep: this.xHighestCompleteStep[j - 2] }, thisStep: { startValue: this.xVal[j - 1], step: this.xNumSteps[j - 1], highestStep: this.xHighestCompleteStep[j - 1] }, stepAfter: { startValue: this.xVal[j], step: this.xNumSteps[j], highestStep: this.xHighestCompleteStep[j] } }; }; Spectrum.prototype.countStepDecimals = function () { var stepDecimals = this.xNumSteps.map(countDecimals); return Math.max.apply(null, stepDecimals); }; // Outside testing Spectrum.prototype.convert = function (value) { return this.getStep(this.toStepping(value)); }; //endregion //region Options /* Every input option is tested and parsed. This'll prevent endless validation in internal methods. These tests are structured with an item for every option available. An option can be marked as required by setting the 'r' flag. The testing function is provided with three arguments: - The provided value for the option; - A reference to the options object; - The name for the option; The testing function returns false when an error is detected, or true when everything is OK. It can also modify the option object, to make sure all values can be correctly looped elsewhere. */ //region Defaults var defaultFormatter = { to: function to(value) { return value !== undefined && value.toFixed(2); }, from: Number }; var cssClasses = { target: "target", base: "base", origin: "origin", handle: "handle", handleLower: "handle-lower", handleUpper: "handle-upper", touchArea: "touch-area", horizontal: "horizontal", vertical: "vertical", background: "background", connect: "connect", connects: "connects", ltr: "ltr", rtl: "rtl", textDirectionLtr: "txt-dir-ltr", textDirectionRtl: "txt-dir-rtl", draggable: "draggable", drag: "state-drag", tap: "state-tap", active: "active", tooltip: "tooltip", pips: "pips", pipsHorizontal: "pips-horizontal", pipsVertical: "pips-vertical", marker: "marker", markerHorizontal: "marker-horizontal", markerVertical: "marker-vertical", markerNormal: "marker-normal", markerLarge: "marker-large", markerSub: "marker-sub", value: "value", valueHorizontal: "value-horizontal", valueVertical: "value-vertical", valueNormal: "value-normal", valueLarge: "value-large", valueSub: "value-sub" }; // Namespaces of internal event listeners var INTERNAL_EVENT_NS = { tooltips: ".__tooltips", aria: ".__aria" }; //endregion function validateFormat(entry) { // Any object with a to and from method is supported. if (isValidFormatter(entry)) { return true; } throw new Error("noUiSlider (" + VERSION + "): 'format' requires 'to' and 'from' methods."); } function testStep(parsed, entry) { if (!isNumeric(entry)) { throw new Error("noUiSlider (" + VERSION + "): 'step' is not numeric."); } // The step option can still be used to set stepping // for linear sliders. Overwritten if set in 'range'. parsed.singleStep = entry; } function testKeyboardPageMultiplier(parsed, entry) { if (!isNumeric(entry)) { throw new Error("noUiSlider (" + VERSION + "): 'keyboardPageMultiplier' is not numeric."); } parsed.keyboardPageMultiplier = entry; } function testKeyboardDefaultStep(parsed, entry) { if (!isNumeric(entry)) { throw new Error("noUiSlider (" + VERSION + "): 'keyboardDefaultStep' is not numeric."); } parsed.keyboardDefaultStep = entry; } function testRange(parsed, entry) { // Filter incorrect input. if ((typeof entry === "undefined" ? "undefined" : _typeof(entry)) !== "object" || Array.isArray(entry)) { throw new Error("noUiSlider (" + VERSION + "): 'range' is not an object."); } // Catch missing start or end. if (entry.min === undefined || entry.max === undefined) { throw new Error("noUiSlider (" + VERSION + "): Missing 'min' or 'max' in 'range'."); } // Catch equal start or end. if (entry.min === entry.max) { throw new Error("noUiSlider (" + VERSION + "): 'range' 'min' and 'max' cannot be equal."); } parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.singleStep); } function testStart(parsed, entry) { entry = asArray(entry); // Validate input. Values aren't tested, as the public .val method // will always provide a valid location. if (!Array.isArray(entry) || !entry.length) { throw new Error("noUiSlider (" + VERSION + "): 'start' option is incorrect."); } // Store the number of handles. parsed.handles = entry.length; // When the slider is initialized, the .val method will // be called with the start options. parsed.start = entry; } function testSnap(parsed, entry) { // Enforce 100% stepping within subranges. parsed.snap = entry; if (typeof entry !== "boolean") { throw new Error("noUiSlider (" + VERSION + "): 'snap' option must be a boolean."); } } function testAnimate(parsed, entry) { // Enforce 100% stepping within subranges. parsed.animate = entry; if (typeof entry !== "boolean") { throw new Error("noUiSlider (" + VERSION + "): 'animate' option must be a boolean."); } } function testAnimationDuration(parsed, entry) { parsed.animationDuration = entry; if (typeof entry !== "number") { throw new Error("noUiSlider (" + VERSION + "): 'animationDuration' option must be a number."); } } function testConnect(parsed, entry) { var connect = [false]; var i; // Map legacy options if (entry === "lower") { entry = [true, false]; } else if (entry === "upper") { entry = [false, true]; } // Handle boolean options if (entry === true || entry === false) { for (i = 1; i < parsed.handles; i++) { connect.push(entry); } connect.push(false); } // Reject invalid input else if (!Array.isArray(entry) || !entry.length || entry.length !== parsed.handles + 1) { throw new Error("noUiSlider (" + VERSION + "): 'connect' option doesn't match handle count."); } else { connect = entry; } parsed.connect = connect; } function testOrientation(parsed, entry) { // Set orientation to an a numerical value for easy // array selection. switch (entry) { case "horizontal": parsed.ort = 0; break; case "vertical": parsed.ort = 1; break; default: throw new Error("noUiSlider (" + VERSION + "): 'orientation' option is invalid."); } } function testMargin(parsed, entry) { if (!isNumeric(entry)) { throw new Error("noUiSlider (" + VERSION + "): 'margin' option must be numeric."); } // Issue #582 if (entry === 0) { return; } parsed.margin = parsed.spectrum.getDistance(entry); } function testLimit(parsed, entry) { if (!isNumeric(entry)) { throw new Error("noUiSlider (" + VERSION + "): 'limit' option must be numeric."); } parsed.limit = parsed.spectrum.getDistance(entry); if (!parsed.limit || parsed.handles < 2) { throw new Error("noUiSlider (" + VERSION + "): 'limit' option is only supported on linear sliders with 2 or more handles."); } } function testPadding(parsed, entry) { var index; if (!isNumeric(entry) && !Array.isArray(entry)) { throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be numeric or array of exactly 2 numbers."); } if (Array.isArray(entry) && !(entry.length === 2 || isNumeric(entry[0]) || isNumeric(entry[1]))) { throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be numeric or array of exactly 2 numbers."); } if (entry === 0) { return; } if (!Array.isArray(entry)) { entry = [entry, entry]; } // 'getDistance' returns false for invalid values. parsed.padding = [parsed.spectrum.getDistance(entry[0]), parsed.spectrum.getDistance(entry[1])]; for (index = 0; index < parsed.spectrum.xNumSteps.length - 1; index++) { // last "range" can't contain step size as it is purely an endpoint. if (parsed.padding[0][index] < 0 || parsed.padding[1][index] < 0) { throw new Error("noUiSlider (" + VERSION + "): 'padding' option must be a positive number(s)."); } } var totalPadding = entry[0] + entry[1]; var firstValue = parsed.spectrum.xVal[0]; var lastValue = parsed.spectrum.xVal[parsed.spectrum.xVal.length - 1]; if (totalPadding / (lastValue - firstValue) > 1) { throw new Error("noUiSlider (" + VERSION + "): 'padding' option must not exceed 100% of the range."); } } function testDirection(parsed, entry) { // Set direction as a numerical value for easy parsing. // Invert connection for RTL sliders, so that the proper // handles get the connect/background classes. switch (entry) { case "ltr": parsed.dir = 0; break; case "rtl": parsed.dir = 1; break; default: throw new Error("noUiSlider (" + VERSION + "): 'direction' option was not recognized."); } } function testBehaviour(parsed, entry) { // Make sure the input is a string. if (typeof entry !== "string") { throw new Error("noUiSlider (" + VERSION + "): 'behaviour' must be a string containing options."); } // Check if the string contains any keywords. // None are required. var tap = entry.indexOf("tap") >= 0; var drag = entry.indexOf("drag") >= 0; var fixed = entry.indexOf("fixed") >= 0; var snap = entry.indexOf("snap") >= 0; var hover = entry.indexOf("hover") >= 0; var unconstrained = entry.indexOf("unconstrained") >= 0; if (fixed) { if (parsed.handles !== 2) { throw new Error("noUiSlider (" + VERSION + "): 'fixed' behaviour must be used with 2 handles"); } // Use margin to enforce fixed state testMargin(parsed, parsed.start[1] - parsed.start[0]); } if (unconstrained && (parsed.margin || parsed.limit)) { throw new Error("noUiSlider (" + VERSION + "): 'unconstrained' behaviour cannot be used with margin or limit"); } parsed.events = { tap: tap || snap, drag: drag, fixed: fixed, snap: snap, hover: hover, unconstrained: unconstrained }; } function testTooltips(parsed, entry) { if (entry === false) { return; } if (entry === true) { parsed.tooltips = []; for (var i = 0; i < parsed.handles; i++) { parsed.tooltips.push(true); } } else { parsed.tooltips = asArray(entry); if (parsed.tooltips.length !== parsed.handles) { throw new Error("noUiSlider (" + VERSION + "): must pass a formatter for all handles."); } parsed.tooltips.forEach(function (formatter) { if (typeof formatter !== "boolean" && ((typeof formatter === "undefined" ? "undefined" : _typeof(formatter)) !== "object" || typeof formatter.to !== "function")) { throw new Error("noUiSlider (" + VERSION + "): 'tooltips' must be passed a formatter or 'false'."); } }); } } function testAriaFormat(parsed, entry) { parsed.ariaFormat = entry; validateFormat(entry); } function testFormat(parsed, entry) { parsed.format = entry; validateFormat(entry); } function testKeyboardSupport(parsed, entry) { parsed.keyboardSupport = entry; if (typeof entry !== "boolean") { throw new Error("noUiSlider (" + VERSION + "): 'keyboardSupport' option must be a boolean."); } } function testDocumentElement(parsed, entry) { // This is an advanced option. Passed values are used without validation. parsed.documentElement = entry; } function testCssPrefix(parsed, entry) { if (typeof entry !== "string" && entry !== false) { throw new Error("noUiSlider (" + VERSION + "): 'cssPrefix' must be a string or `false`."); } parsed.cssPrefix = entry; } function testCssClasses(parsed, entry) { if ((typeof entry === "undefined" ? "undefined" : _typeof(entry)) !== "object") { throw new Error("noUiSlider (" + VERSION + "): 'cssClasses' must be an object."); } if (typeof parsed.cssPrefix === "string") { parsed.cssClasses = {}; for (var key in entry) { if (!entry.hasOwnProperty(key)) { continue; } parsed.cssClasses[key] = parsed.cssPrefix + entry[key]; } } else { parsed.cssClasses = entry; } } // Test all developer settings and parse to assumption-safe values. function testOptions(options) { // To prove a fix for #537, freeze options here. // If the object is modified, an error will be thrown. // Object.freeze(options); var parsed = { margin: 0, limit: 0, padding: 0, animate: true, animationDuration: 300, ariaFormat: defaultFormatter, format: defaultFormatter }; // Tests are executed in the order they are presented here. var tests = { step: { r: false, t: testStep }, keyboardPageMultiplier: { r: false, t: testKeyboardPageMultiplier }, keyboardDefaultStep: { r: false, t: testKeyboardDefaultStep }, start: { r: true, t: testStart }, connect: { r: true, t: testConnect }, direction: { r: true, t: testDirection }, snap: { r: false, t: testSnap }, animate: { r: false, t: testAnimate }, animationDuration: { r: false, t: testAnimationDuration }, range: { r: true, t: testRange }, orientation: { r: false, t: testOrientation }, margin: { r: false, t: testMargin }, limit: { r: false, t: testLimit }, padding: { r: false, t: testPadding }, behaviour: { r: true, t: testBehaviour }, ariaFormat: { r: false, t: testAriaFormat }, format: { r: false, t: testFormat }, tooltips: { r: false, t: testTooltips }, keyboardSupport: { r: true, t: testKeyboardSupport }, documentElement: { r: false, t: testDocumentElement }, cssPrefix: { r: true, t: testCssPrefix }, cssClasses: { r: true, t: testCssClasses } }; var defaults = { connect: false, direction: "ltr", behaviour: "tap", orientation: "horizontal", keyboardSupport: true, cssPrefix: "ui-slider-", cssClasses: cssClasses, keyboardPageMultiplier: 5, keyboardDefaultStep: 10 }; // AriaFormat defaults to regular format, if any. if (options.format && !options.ariaFormat) { options.ariaFormat = options.format; } // Run all options through a testing mechanism to ensure correct // input. It should be noted that options might get modified to // be handled properly. E.g. wrapping integers in arrays. Object.keys(tests).forEach(function (name) { // If the option isn't set, but it is required, throw an error. if (!isSet(options[name]) && defaults[name] === undefined) { if (tests[name].r) { throw new Error("noUiSlider (" + VERSION + "): '" + name + "' is required."); } return true; } tests[name].t(parsed, !isSet(options[name]) ? defaults[name] : options[name]); }); // Forward pips options parsed.pips = options.pips; // All recent browsers accept unprefixed transform. // We need -ms- for IE9 and -webkit- for older Android; // Assume use of -webkit- if unprefixed and -ms- are not supported. // https://caniuse.com/#feat=transforms2d var d = document.createElement("div"); var msPrefix = d.style.msTransform !== undefined; var noPrefix = d.style.transform !== undefined; parsed.transformRule = noPrefix ? "transform" : msPrefix ? "msTransform" : "webkitTransform"; // Pips don't move, so we can place them using left/top. var styles = [["left", "top"], ["right", "bottom"]]; parsed.style = styles[parsed.dir][parsed.ort]; return parsed; } //endregion function scope(target, options, originalOptions) { var actions = getActions(); var supportsTouchActionNone = getSupportsTouchActionNone(); var supportsPassive = supportsTouchActionNone && getSupportsPassive(); // All variables local to 'scope' are prefixed with 'scope_' // Slider DOM Nodes var scope_Target = target; var scope_Base; var scope_Handles; var scope_Connects; var scope_Pips; var scope_Tooltips; // Slider state values var scope_Spectrum = options.spectrum; var scope_Values = []; var scope_Locations = []; var scope_HandleNumbers = []; var scope_ActiveHandlesCount = 0; var scope_Events = {}; // Exposed API var scope_Self; // Document Nodes var scope_Document = target.ownerDocument; var scope_DocumentElement = options.documentElement || scope_Document.documentElement; var scope_Body = scope_Document.body; // Pips constants var PIPS_NONE = -1; var PIPS_NO_VALUE = 0; var PIPS_LARGE_VALUE = 1; var PIPS_SMALL_VALUE = 2; // For horizontal sliders in standard ltr documents, // make .noUi-origin overflow to the left so the document doesn't scroll. var scope_DirOffset = scope_Document.dir === "rtl" || options.ort === 1 ? 0 : 100; // Creates a node, adds it to target, returns the new node. function addNodeTo(addTarget, className) { var div = scope_Document.createElement("div"); if (className) { addClass(div, className); } addTarget.appendChild(div); return div; } // Append a origin to the base function addOrigin(base, handleNumber) { var origin = addNodeTo(base, options.cssClasses.origin); var handle = addNodeTo(origin, options.cssClasses.handle); addNodeTo(handle, options.cssClasses.touchArea); handle.setAttribute("data-handle", handleNumber); if (options.keyboardSupport) { // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex // 0 = focusable and reachable handle.setAttribute("tabindex", "0"); handle.addEventListener("keydown", function (event) { return eventKeydown(event, handleNumber); }); } handle.setAttribute("role", "slider"); handle.setAttribute("aria-orientation", options.ort ? "vertical" : "horizontal"); if (handleNumber === 0) { addClass(handle, options.cssClasses.handleLower); } else if (handleNumber === options.handles - 1) { addClass(handle, options.cssClasses.handleUpper); } return origin; } // Insert nodes for connect elements function addConnect(base, add) { if (!add) { return false; } return addNodeTo(base, options.cssClasses.connect); } // Add handles to the slider base. function addElements(connectOptions, base) { var connectBase = addNodeTo(base, options.cssClasses.connects); scope_Handles = []; scope_Connects = []; scope_Connects.push(addConnect(connectBase, connectOptions[0])); // [::::O====O====O====] // connectOptions = [0, 1, 1, 1] for (var i = 0; i < options.handles; i++) { // Keep a list of all added handles. scope_Handles.push(addOrigin(base, i)); scope_HandleNumbers[i] = i; scope_Connects.push(addConnect(connectBase, connectOptions[i + 1])); } } // Initialize a single slider. function addSlider(addTarget) { // Apply classes and data to the target. addClass(addTarget, options.cssClasses.target); if (options.dir === 0) { addClass(addTarget, options.cssClasses.ltr); } else { addClass(addTarget, options.cssClasses.rtl); } if (options.ort === 0) { addClass(addTarget, options.cssClasses.horizontal); } else { addClass(addTarget, options.cssClasses.vertical); } var textDirection = getComputedStyle(addTarget).direction; if (textDirection === "rtl") { addClass(addTarget, options.cssClasses.textDirectionRtl); } else { addClass(addTarget, options.cssClasses.textDirectionLtr); } return addNodeTo(addTarget, options.cssClasses.base); } function addTooltip(handle, handleNumber) { if (!options.tooltips[handleNumber]) { return false; } return addNodeTo(handle.firstChild, options.cssClasses.tooltip); } function isSliderDisabled() { return scope_Target.hasAttribute("disabled"); } // Disable the slider dragging if any handle is disabled function isHandleDisabled(handleNumber) { var handleOrigin = scope_Handles[handleNumber]; return handleOrigin.hasAttribute("disabled"); } function removeTooltips() { if (scope_Tooltips) { removeEvent("update" + INTERNAL_EVENT_NS.tooltips); scope_Tooltips.forEach(function (tooltip) { if (tooltip) { removeElement(tooltip); } }); scope_Tooltips = null; } } // The tooltips option is a shorthand for using the 'update' event. function tooltips() { removeTooltips(); // Tooltips are added with options.tooltips in original order. scope_Tooltips = scope_Handles.map(addTooltip); bindEvent("update" + INTERNAL_EVENT_NS.tooltips, function (values, handleNumber, unencoded) { if (!scope_Tooltips[handleNumber]) { return; } var formattedValue = values[handleNumber]; if (options.tooltips[handleNumber] !== true) { formattedValue = options.tooltips[handleNumber].to(unencoded[handleNumber]); } scope_Tooltips[handleNumber].innerHTML = formattedValue; }); } function aria() { removeEvent("update" + INTERNAL_EVENT_NS.aria); bindEvent("update" + INTERNAL_EVENT_NS.aria, function (values, handleNumber, unencoded, tap, positions) { // Update Aria Values for all handles, as a change in one changes min and max values for the next. scope_HandleNumbers.forEach(function (index) { var handle = scope_Handles[index]; var min = checkHandlePosition(scope_Locations, index, 0, true, true, true); var max = checkHandlePosition(scope_Locations, index, 100, true, true, true); var now = positions[index]; // Formatted value for display var text = options.ariaFormat.to(unencoded[index]); // Map to slider range values min = scope_Spectrum.fromStepping(min).toFixed(1); max = scope_Spectrum.fromStepping(max).toFixed(1); now = scope_Spectrum.fromStepping(now).toFixed(1); handle.children[0].setAttribute("aria-valuemin", min); handle.children[0].setAttribute("aria-valuemax", max); handle.children[0].setAttribute("aria-valuenow", now); handle.children[0].setAttribute("aria-valuetext", text); }); }); } function getGroup(mode, values, stepped) { // Use the range. if (mode === "range" || mode === "steps") { return scope_Spectrum.xVal; } if (mode === "count") { if (values < 2) { throw new Error("noUiSlider (" + VERSION + "): 'values' (>= 2) required for mode 'count'."); } // Divide 0 - 100 in 'count' parts. var interval = values - 1; var spread = 100 / interval; values = []; // List these parts and have them handled as 'positions'. while (interval--) { values[interval] = interval * spread; } values.push(100); mode = "positions"; } if (mode === "positions") { // Map all percentages to on-range values. return values.map(function (value) { return scope_Spectrum.fromStepping(stepped ? scope_Spectrum.getStep(value) : value); }); } if (mode === "values") { // If the value must be stepped, it needs to be converted to a percentage first. if (stepped) { return values.map(function (value) { // Convert to percentage, apply step, return to value. return scope_Spectrum.fromStepping(scope_Spectrum.getStep(scope_Spectrum.toStepping(value))); }); } // Otherwise, we can simply use the values. return values; } } function generateSpread(density, mode, group) { function safeIncrement(value, increment) { // Avoid floating point variance by dropping the smallest decimal places. return (value + increment).toFixed(7) / 1; } var indexes = {}; var firstInRange = scope_Spectrum.xVal[0]; var lastInRange = scope_Spectrum.xVal[scope_Spectrum.xVal.length - 1]; var ignoreFirst = false; var ignoreLast = false; var prevPct = 0; // Create a copy of the group, sort it and filter away all duplicates. group = unique(group.slice().sort(function (a, b) { return a - b; })); // Make sure the range starts with the first element. if (group[0] !== firstInRange) { group.unshift(firstInRange); ignoreFirst = true; } // Likewise for the last one. if (group[group.length - 1] !== lastInRange) { group.push(lastInRange); ignoreLast = true; } group.forEach(function (current, index) { // Get the current step and the lower + upper positions. var step; var i; var q; var low = current; var high = group[index + 1]; var newPct; var pctDifference; var pctPos; var type; var steps; var realSteps; var stepSize; var isSteps = mode === "steps"; // When using 'steps' mode, use the provided steps. // Otherwise, we'll step on to the next subrange. if (isSteps) { step = scope_Spectrum.xNumSteps[index]; } // Default to a 'full' step. if (!step) { step = high - low; } // Low can be 0, so test for false. Index 0 is already handled. if (low === false) { return; } // If high is undefined we are at the last subrange. Make sure it iterates once (#1088) if (high === undefined) { high = low; } // Make sure step isn't 0, which would cause an infinite loop (#654) step = Math.max(step, 0.0000001); // Find all steps in the subrange. for (i = low; i <= high; i = safeIncrement(i, step)) { // Get the percentage value for the current step, // calculate the size for the subrange. newPct = scope_Spectrum.toStepping(i); pctDifference = newPct - prevPct; steps = pctDifference / density; realSteps = Math.round(steps); // This ratio represents the amount of percentage-space a point indicates. // For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-divided. // Round the percentage offset to an even number, then divide by two // to spread the offset on both sides of the range. stepSize = pctDifference / realSteps; // Divide all points evenly, adding the correct number to this subrange. // Run up to <= so that 100% gets a point, event if ignoreLast is set. for (q = 1; q <= realSteps; q += 1) { // The ratio between the rounded value and the actual size might be ~1% off. // Correct the percentage offset by the number of points // per subrange. density = 1 will result in 100 points on the // full range, 2 for 50, 4 for 25, etc. pctPos = prevPct + q * stepSize; indexes[pctPos.toFixed(5)] = [scope_Spectrum.fromStepping(pctPos), 0]; } // Determine the point type. type = group.indexOf(i) > -1 ? PIPS_LARGE_VALUE : isSteps ? PIPS_SMALL_VALUE : PIPS_NO_VALUE; // Enforce the 'ignoreFirst' option by overwriting the type for 0. if (!index && ignoreFirst && i !== high) { type = 0; } if (!(i === high && ignoreLast)) { // Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value. indexes[newPct.toFixed(5)] = [i, type]; } // Update the percentage count. prevPct = newPct; } }); return indexes; } function addMarking(spread, filterFunc, formatter) { var element = scope_Document.createElement("div"); var valueSizeClasses = []; valueSizeClasses[PIPS_NO_VALUE] = options.cssClasses.valueNormal; valueSizeClasses[PIPS_LARGE_VALUE] = options.cssClasses.valueLarge; valueSizeClasses[PIPS_SMALL_VALUE] = options.cssClasses.valueSub; var markerSizeClasses = []; markerSizeClasses[PIPS_NO_VALUE] = options.cssClasses.markerNormal; markerSizeClasses[PIPS_LARGE_VALUE] = options.cssClasses.markerLarge; markerSizeClasses[PIPS_SMALL_VALUE] = options.cssClasses.markerSub; var valueOrientationClasses = [options.cssClasses.valueHorizontal, options.cssClasses.valueVertical]; var markerOrientationClasses = [options.cssClasses.markerHorizontal, options.cssClasses.markerVertical]; addClass(element, options.cssClasses.pips); addClass(element, options.ort === 0 ? options.cssClasses.pipsHorizontal : options.cssClasses.pipsVertical); function getClasses(type, source) { var a = source === options.cssClasses.value; var orientationClasses = a ? valueOrientationClasses : markerOrientationClasses; var sizeClasses = a ? valueSizeClasses : markerSizeClasses; return source + " " + orientationClasses[options.ort] + " " + sizeClasses[type]; } function addSpread(offset, value, type) { // Apply the filter function, if it is set. type = filterFunc ? filterFunc(value, type) : type; if (type === PIPS_NONE) { return; } // Add a marker for every point var node = addNodeTo(element, false); node.className = getClasses(type, options.cssClasses.marker); node.style[options.style] = offset + "%"; // Values are only appended for points marked '1' or '2'. if (type > PIPS_NO_VALUE) { node = addNodeTo(element, false); node.className = getClasses(type, options.cssClasses.value); node.setAttribute("data-value", value); node.style[options.style] = offset + "%"; node.innerHTML = formatter.to(value); } } // Append all points. Object.keys(spread).forEach(function (offset) { addSpread(offset, spread[offset][0], spread[offset][1]); }); return element; } function removePips() { if (scope_Pips) { removeElement(scope_Pips); scope_Pips = null; } } function pips(grid) { // Fix #669 removePips(); var mode = grid.mode; var density = grid.density || 1; var filter = grid.filter || false; var values = grid.values || false; var stepped = grid.stepped || false; var group = getGroup(mode, values, stepped); var spread = generateSpread(density, mode, group); var format = grid.format || { to: Math.round }; scope_Pips = scope_Target.appendChild(addMarking(spread, filter, format)); return scope_Pips; } // Shorthand for base dimensions. function baseSize() { var rect = scope_Base.getBoundingClientRect(); var alt = "offset" + ["Width", "Height"][options.ort]; return options.ort === 0 ? rect.width || scope_Base[alt] : rect.height || scope_Base[alt]; } // Handler for attaching events trough a proxy. function attachEvent(events, element, callback, data) { // This function can be used to 'filter' events to the slider. // element is a node, not a nodeList var method = function method(e) { e = fixEvent(e, data.pageOffset, data.target || element); // fixEvent returns false if this event has a different target // when handling (multi-) touch events; if (!e) { return false; } // doNotReject is passed by all end events to make sure released touches // are not rejected, leaving the slider "stuck" to the cursor; if (isSliderDisabled() && !data.doNotReject) { return false; } // Stop if an active 'tap' transition is taking place. if (hasClass(scope_Target, options.cssClasses.tap) && !data.doNotReject) { return false; } // Ignore right or middle clicks on start #454 if (events === actions.start && e.buttons !== undefined && e.buttons > 1) { return false; } // Ignore right or middle clicks on start #454 if (data.hover && e.buttons) { return false; } // 'supportsPassive' is only true if a browser also supports touch-action: none in CSS. // iOS safari does not, so it doesn't get to benefit from passive scrolling. iOS does support // touch-action: manipulation, but that allows panning, which breaks // sliders after zooming/on non-responsive pages. // See: https://bugs.webkit.org/show_bug.cgi?id=133112 if (!supportsPassive) { e.preventDefault(); } e.calcPoint = e.points[options.ort]; // Call the event handler with the event [ and additional data ]. callback(e, data); }; var methods = []; // Bind a closure on the target for every event type. events.split(" ").forEach(function (eventName) { element.addEventListener(eventName, method, supportsPassive ? { passive: true } : false); methods.push([eventName, method]); }); return methods; } // Provide a clean event with standardized offset values. function fixEvent(e, pageOffset, eventTarget) { // Filter the event to register the type, which can be // touch, mouse or pointer. Offset changes need to be // made on an event specific basis. var touch = e.type.indexOf("touch") === 0; var mouse = e.type.indexOf("mouse") === 0; var pointer = e.type.indexOf("pointer") === 0; var x; var y; // IE10 implemented pointer events with a prefix; if (e.type.indexOf("MSPointer") === 0) { pointer = true; } // Erroneous events seem to be passed in occasionally on iOS/iPadOS after user finishes interacting with // the slider. They appear to be of type MouseEvent, yet they don't have usual properties set. Ignore // events that have no touches or buttons associated with them. (#1057, #1079, #1095) if (e.type === "mousedown" && !e.buttons && !e.touches) { return false; } // The only thing one handle should be concerned about is the touches that originated on top of it. if (touch) { // Returns true if a touch originated on the target. var isTouchOnTarget = function isTouchOnTarget(checkTouch) { return checkTouch.target === eventTarget || eventTarget.contains(checkTouch.target) || checkTouch.target.shadowRoot && checkTouch.target.shadowRoot.contains(eventTarget); }; // In the case of touchstart events, we need to make sure there is still no more than one // touch on the target so we look amongst all touches. if (e.type === "touchstart") { var targetTouches = Array.prototype.filter.call(e.touches, isTouchOnTarget); // Do not support more than one touch per handle. if (targetTouches.length > 1) { return false; } x = targetTouches[0].pageX; y = targetTouches[0].pageY; } else { // In the other cases, find on changedTouches is enough. var targetTouch = Array.prototype.find.call(e.changedTouches, isTouchOnTarget); // Cancel if the target touch has not moved. if (!targetTouch) { return false; } x = targetTouch.pageX; y = targetTouch.pageY; } } pageOffset = pageOffset || getPageOffset(scope_Document); if (mouse || pointer) { x = e.clientX + pageOffset.x; y = e.clientY + pageOffset.y; } e.pageOffset = pageOffset; e.points = [x, y]; e.cursor = mouse || pointer; // Fix #435 return e; } // Translate a coordinate in the document to a percentage on the slider function calcPointToPercentage(calcPoint) { var location = calcPoint - offset(scope_Base, options.ort); var proposal = location * 100 / baseSize(); // Clamp proposal between 0% and 100% // Out-of-bound coordinates may occur when .noUi-base pseudo-elements // are used (e.g. contained handles feature) proposal = limit(proposal); return options.dir ? 100 - proposal : proposal; } // Find handle closest to a certain percentage on the slider function getClosestHandle(clickedPosition) { var smallestDifference = 100; var handleNumber = false; scope_Handles.forEach(function (handle, index) { // Disabled handles are ignored if (isHandleDisabled(index)) { return; } var handlePosition = scope_Locations[index]; var differenceWithThisHandle = Math.abs(handlePosition - clickedPosition); // Initial state var clickAtEdge = differenceWithThisHandle === 100 && smallestDifference === 100; // Difference with this handle is smaller than the previously checked handle var isCloser = differenceWithThisHandle < smallestDifference; var isCloserAfter = differenceWithThisHandle <= smallestDifference && clickedPosition > handlePosition; if (isCloser || isCloserAfter || clickAtEdge) { handleNumber = index; smallestDifference = differenceWithThisHandle; } }); return handleNumber; } // Fire 'end' when a mouse or pen leaves the document. function documentLeave(event, data) { if (event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null) { eventEnd(event, data); } } // Handle movement on document for handle and range drag. function eventMove(event, data) { // Fix #498 // Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty). // https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero // IE9 has .buttons and .which zero on mousemove. // Firefox breaks the spec MDN defines. if (navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0) { return eventEnd(event, data); } // Check if we are moving up or down var movement = (options.dir ? -1 : 1) * (event.calcPoint - data.startCalcPoint); // Convert the movement into a percentage of the slider width/height var proposal = movement * 100 / data.baseSize; moveHandles(movement > 0, proposal, data.locations, data.handleNumbers); } // Unbind move events on document, call callbacks. function eventEnd(event, data) { // The handle is no longer active, so remove the class. if (data.handle) { removeClass(data.handle, options.cssClasses.active); scope_ActiveHandlesCount -= 1; } // Unbind the move and end events, which are added on 'start'. data.listeners.forEach(function (c) { scope_DocumentElement.removeEventListener(c[0], c[1]); }); if (scope_ActiveHandlesCount === 0) { // Remove dragging class. removeClass(scope_Target, options.cssClasses.drag); setZindex(); // Remove cursor styles and text-selection events bound to the body. if (event.cursor) { scope_Body.style.cursor = ""; scope_Body.removeEventListener("selectstart", preventDefault); } } data.handleNumbers.forEach(function (handleNumber) { fireEvent("change", handleNumber); fireEvent("set", handleNumber); fireEvent("end", handleNumber); }); } // Bind move events on document. function eventStart(event, data) { // Ignore event if any handle is disabled if (data.handleNumbers.some(isHandleDisabled)) { return false; } var handle; if (data.handleNumbers.length === 1) { var handleOrigin = scope_Handles[data.handleNumbers[0]]; handle = handleOrigin.children[0]; scope_ActiveHandlesCount += 1; // Mark the handle as 'active' so it can be styled. addClass(handle, options.cssClasses.active); } // A drag should never propagate up to the 'tap' event. event.stopPropagation(); // Record the event listeners. var listeners = []; // Attach the move and end events. var moveEvent = attachEvent(actions.move, scope_DocumentElement, eventMove, { // The event target has changed so we need to propagate the original one so that we keep // relying on it to extract target touches. target: event.target, handle: handle, listeners: listeners, startCalcPoint: event.calcPoint, baseSize: baseSize(), pageOffset: event.pageOffset, handleNumbers: data.handleNumbers, buttonsProperty: event.buttons, locations: scope_Locations.slice() }); var endEvent = attachEvent(actions.end, scope_DocumentElement, eventEnd, { target: event.target, handle: handle, listeners: listeners, doNotReject: true, handleNumbers: data.handleNumbers }); var outEvent = attachEvent("mouseout", scope_DocumentElement, documentLeave, { target: event.target, handle: handle, listeners: listeners, doNotReject: true, handleNumbers: data.handleNumbers }); // We want to make sure we pushed the listeners in the listener list rather than creating // a new one as it has already been passed to the event handlers. listeners.push.apply(listeners, moveEvent.concat(endEvent, outEvent)); // Text selection isn't an issue on touch devices, // so adding cursor styles can be skipped. if (event.cursor) { // Prevent the 'I' cursor and extend the range-drag cursor. scope_Body.style.cursor = getComputedStyle(event.target).cursor; // Mark the target with a dragging state. if (scope_Handles.length > 1) { addClass(scope_Target, options.cssClasses.drag); } // Prevent text selection when dragging the handles. // In noUiSlider <= 9.2.0, this was handled by calling preventDefault on mouse/touch start/move, // which is scroll blocking. The selectstart event is supported by FireFox starting from version 52, // meaning the only holdout is iOS Safari. This doesn't matter: text selection isn't triggered there. // The 'cursor' flag is false. // See: http://caniuse.com/#search=selectstart scope_Body.addEventListener("selectstart", preventDefault, false); } data.handleNumbers.forEach(function (handleNumber) { fireEvent("start", handleNumber); }); } // Move closest handle to tapped location. function eventTap(event) { // The tap event shouldn't propagate up event.stopPropagation(); var proposal = calcPointToPercentage(event.calcPoint); var handleNumber = getClosestHandle(proposal); // Tackle the case that all handles are 'disabled'. if (handleNumber === false) { return false; } // Flag the slider as it is now in a transitional state. // Transition takes a configurable amount of ms (default 300). Re-enable the slider after that. if (!options.events.snap) { addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration); } setHandle(handleNumber, proposal, true, true); setZindex(); fireEvent("slide", handleNumber, true); fireEvent("update", handleNumber, true); fireEvent("change", handleNumber, true); fireEvent("set", handleNumber, true); if (options.events.snap) { eventStart(event, { handleNumbers: [handleNumber] }); } } // Fires a 'hover' event for a hovered mouse/pen position. function eventHover(event) { var proposal = calcPointToPercentage(event.calcPoint); var to = scope_Spectrum.getStep(proposal); var value = scope_Spectrum.fromStepping(to); Object.keys(scope_Events).forEach(function (targetEvent) { if ("hover" === targetEvent.split(".")[0]) { scope_Events[targetEvent].forEach(function (callback) { callback.call(scope_Self, value); }); } }); } // Handles keydown on focused handles // Don't move the document when pressing arrow keys on focused handles function eventKeydown(event, handleNumber) { if (isSliderDisabled() || isHandleDisabled(handleNumber)) { return false; } var horizontalKeys = ["Left", "Right"]; var verticalKeys = ["Down", "Up"]; var largeStepKeys = ["PageDown", "PageUp"]; var edgeKeys = ["Home", "End"]; if (options.dir && !options.ort) { // On an right-to-left slider, the left and right keys act inverted horizontalKeys.reverse(); } else if (options.ort && !options.dir) { // On a top-to-bottom slider, the up and down keys act inverted verticalKeys.reverse(); largeStepKeys.reverse(); } // Strip "Arrow" for IE compatibility. https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key var key = event.key.replace("Arrow", ""); var isLargeDown = key === largeStepKeys[0]; var isLargeUp = key === largeStepKeys[1]; var isDown = key === verticalKeys[0] || key === horizontalKeys[0] || isLargeDown; var isUp = key === verticalKeys[1] || key === horizontalKeys[1] || isLargeUp; var isMin = key === edgeKeys[0]; var isMax = key === edgeKeys[1]; if (!isDown && !isUp && !isMin && !isMax) { return true; } event.preventDefault(); var to; if (isUp || isDown) { var multiplier = options.keyboardPageMultiplier; var direction = isDown ? 0 : 1; var steps = getNextStepsForHandle(handleNumber); var step = steps[direction]; // At the edge of a slider, do nothing if (step === null) { return false; } // No step set, use the default of 10% of the sub-range if (step === false) { step = scope_Spectrum.getDefaultStep(scope_Locations[handleNumber], isDown, options.keyboardDefaultStep); } if (isLargeUp || isLargeDown) { step *= multiplier; } // Step over zero-length ranges (#948); step = Math.max(step, 0.0000001); // Decrement for down steps step = (isDown ? -1 : 1) * step; to = scope_Values[handleNumber] + step; } else if (isMax) { // End key to = options.spectrum.xVal[options.spectrum.xVal.length - 1]; } else { // Home key to = options.spectrum.xVal[0]; } setHandle(handleNumber, scope_Spectrum.toStepping(to), true, true); fireEvent("slide", handleNumber); fireEvent("update", handleNumber); fireEvent("change", handleNumber); fireEvent("set", handleNumber); return false; } // Attach events to several slider parts. function bindSliderEvents(behaviour) { // Attach the standard drag event to the handles. if (!behaviour.fixed) { scope_Handles.forEach(function (handle, index) { // These events are only bound to the visual handle // element, not the 'real' origin element. attachEvent(actions.start, handle.children[0], eventStart, { handleNumbers: [index] }); }); } // Attach the tap event to the slider base. if (behaviour.tap) { attachEvent(actions.start, scope_Base, eventTap, {}); } // Fire hover events if (behaviour.hover) { attachEvent(actions.move, scope_Base, eventHover, { hover: true }); } // Make the range draggable. if (behaviour.drag) { scope_Connects.forEach(function (connect, index) { if (connect === false || index === 0 || index === scope_Connects.length - 1) { return; } var handleBefore = scope_Handles[index - 1]; var handleAfter = scope_Handles[index]; var eventHolders = [connect]; addClass(connect, options.cssClasses.draggable); // When the range is fixed, the entire range can // be dragged by the handles. The handle in the first // origin will propagate the start event upward, // but it needs to be bound manually on the other. if (behaviour.fixed) { eventHolders.push(handleBefore.children[0]); eventHolders.push(handleAfter.children[0]); } eventHolders.forEach(function (eventHolder) { attachEvent(actions.start, eventHolder, eventStart, { handles: [handleBefore, handleAfter], handleNumbers: [index - 1, index] }); }); }); } } // Attach an event to this slider, possibly including a namespace function bindEvent(namespacedEvent, callback) { scope_Events[namespacedEvent] = scope_Events[namespacedEvent] || []; scope_Events[namespacedEvent].push(callback); // If the event bound is 'update,' fire it immediately for all handles. if (namespacedEvent.split(".")[0] === "update") { scope_Handles.forEach(function (a, index) { fireEvent("update", index); }); } } function isInternalNamespace(namespace) { return namespace === INTERNAL_EVENT_NS.aria || namespace === INTERNAL_EVENT_NS.tooltips; } // Undo attachment of event function removeEvent(namespacedEvent) { var event = namespacedEvent && namespacedEvent.split(".")[0]; var namespace = event ? namespacedEvent.substring(event.length) : namespacedEvent; Object.keys(scope_Events).forEach(function (bind) { var tEvent = bind.split(".")[0]; var tNamespace = bind.substring(tEvent.length); if ((!event || event === tEvent) && (!namespace || namespace === tNamespace)) { // only delete protected internal event if intentional if (!isInternalNamespace(tNamespace) || namespace === tNamespace) { delete scope_Events[bind]; } } }); } // External event handling function fireEvent(eventName, handleNumber, tap) { Object.keys(scope_Events).forEach(function (targetEvent) { var eventType = targetEvent.split(".")[0]; if (eventName === eventType) { scope_Events[targetEvent].forEach(function (callback) { callback.call( // Use the slider public API as the scope ('this') scope_Self, // Return values as array, so arg_1[arg_2] is always valid. scope_Values.map(options.format.to), // Handle index, 0 or 1 handleNumber, // Un-formatted slider values scope_Values.slice(), // Event is fired by tap, true or false tap || false, // Left offset of the handle, in relation to the slider scope_Locations.slice(), // add the slider public API to an accessible parameter when this is unavailable scope_Self); }); } }); } // Split out the handle positioning logic so the Move event can use it, too function checkHandlePosition(reference, handleNumber, to, lookBackward, lookForward, getValue) { var distance; // For sliders with multiple handles, limit movement to the other handle. // Apply the margin option by adding it to the handle positions. if (scope_Handles.length > 1 && !options.events.unconstrained) { if (lookBackward && handleNumber > 0) { distance = scope_Spectrum.getAbsoluteDistance(reference[handleNumber - 1], options.margin, 0); to = Math.max(to, distance); } if (lookForward && handleNumber < scope_Handles.length - 1) { distance = scope_Spectrum.getAbsoluteDistance(reference[handleNumber + 1], options.margin, 1); to = Math.min(to, distance); } } // The limit option has the opposite effect, limiting handles to a // maximum distance from another. Limit must be > 0, as otherwise // handles would be unmovable. if (scope_Handles.length > 1 && options.limit) { if (lookBackward && handleNumber > 0) { distance = scope_Spectrum.getAbsoluteDistance(reference[handleNumber - 1], options.limit, 0); to = Math.min(to, distance); } if (lookForward && handleNumber < scope_Handles.length - 1) { distance = scope_Spectrum.getAbsoluteDistance(reference[handleNumber + 1], options.limit, 1); to = Math.max(to, distance); } } // The padding option keeps the handles a certain distance from the // edges of the slider. Padding must be > 0. if (options.padding) { if (handleNumber === 0) { distance = scope_Spectrum.getAbsoluteDistance(0, options.padding[0], 0); to = Math.max(to, distance); } if (handleNumber === scope_Handles.length - 1) { distance = scope_Spectrum.getAbsoluteDistance(100, options.padding[1], 1); to = Math.min(to, distance); } } to = scope_Spectrum.getStep(to); // Limit percentage to the 0 - 100 range to = limit(to); // Return false if handle can't move if (to === reference[handleNumber] && !getValue) { return false; } return to; } // Uses slider orientation to create CSS rules. a = base value; function inRuleOrder(v, a) { var o = options.ort; return (o ? a : v) + ", " + (o ? v : a); } // Moves handle(s) by a percentage // (bool, % to move, [% where handle started, ...], [index in scope_Handles, ...]) function moveHandles(upward, proposal, locations, handleNumbers) { var proposals = locations.slice(); var b = [!upward, upward]; var f = [upward, !upward]; // Copy handleNumbers so we don't change the dataset handleNumbers = handleNumbers.slice(); // Check to see which handle is 'leading'. // If that one can't move the second can't either. if (upward) { handleNumbers.reverse(); } // Step 1: get the maximum percentage that any of the handles can move if (handleNumbers.length > 1) { handleNumbers.forEach(function (handleNumber, o) { var to = checkHandlePosition(proposals, handleNumber, proposals[handleNumber] + proposal, b[o], f[o], false); // Stop if one of the handles can't move. if (to === false) { proposal = 0; } else { proposal = to - proposals[handleNumber]; proposals[handleNumber] = to; } }); } // If using one handle, check backward AND forward else { b = f = [true]; } var state = false; // Step 2: Try to set the handles with the found percentage handleNumbers.forEach(function (handleNumber, o) { state = setHandle(handleNumber, locations[handleNumber] + proposal, b[o], f[o]) || state; }); // Step 3: If a handle moved, fire events if (state) { handleNumbers.forEach(function (handleNumber) { fireEvent("update", handleNumber); fireEvent("slide", handleNumber); }); } } // Takes a base value and an offset. This offset is used for the connect bar size. // In the initial design for this feature, the origin element was 1% wide. // Unfortunately, a rounding bug in Chrome makes it impossible to implement this feature // in this manner: https://bugs.chromium.org/p/chromium/issues/detail?id=798223 function transformDirection(a, b) { return options.dir ? 100 - a - b : a; } // Updates scope_Locations and scope_Values, updates visual state function updateHandlePosition(handleNumber, to) { // Update locations. scope_Locations[handleNumber] = to; // Convert the value to the slider stepping/range. scope_Values[handleNumber] = scope_Spectrum.fromStepping(to); var translation = 10 * (transformDirection(to, 0) - scope_DirOffset); var translateRule = "translate(" + inRuleOrder(translation + "%", "0") + ")"; scope_Handles[handleNumber].style[options.transformRule] = translateRule; updateConnect(handleNumber); updateConnect(handleNumber + 1); } // Handles before the slider middle are stacked later = higher, // Handles after the middle later is lower // [[7] [8] .......... | .......... [5] [4] function setZindex() { scope_HandleNumbers.forEach(function (handleNumber) { var dir = scope_Locations[handleNumber] > 50 ? -1 : 1; var zIndex = 3 + (scope_Handles.length + dir * handleNumber); scope_Handles[handleNumber].style.zIndex = zIndex; }); } // Test suggested values and apply margin, step. // if exactInput is true, don't run checkHandlePosition, then the handle can be placed in between steps (#436) function setHandle(handleNumber, to, lookBackward, lookForward, exactInput) { if (!exactInput) { to = checkHandlePosition(scope_Locations, handleNumber, to, lookBackward, lookForward, false); } if (to === false) { return false; } updateHandlePosition(handleNumber, to); return true; } // Updates style attribute for connect nodes function updateConnect(index) { // Skip connects set to false if (!scope_Connects[index]) { return; } var l = 0; var h = 100; if (index !== 0) { l = scope_Locations[index - 1]; } if (index !== scope_Connects.length - 1) { h = scope_Locations[index]; } // We use two rules: // 'translate' to change the left/top offset; // 'scale' to change the width of the element; // As the element has a width of 100%, a translation of 100% is equal to 100% of the parent (.noUi-base) var connectWidth = h - l; var translateRule = "translate(" + inRuleOrder(transformDirection(l, connectWidth) + "%", "0") + ")"; var scaleRule = "scale(" + inRuleOrder(connectWidth / 100, "1") + ")"; scope_Connects[index].style[options.transformRule] = translateRule + " " + scaleRule; } // Parses value passed to .set method. Returns current value if not parse-able. function resolveToValue(to, handleNumber) { // Setting with null indicates an 'ignore'. // Inputting 'false' is invalid. if (to === null || to === false || to === undefined) { return scope_Locations[handleNumber]; } // If a formatted number was passed, attempt to decode it. if (typeof to === "number") { to = String(to); } to = options.format.from(to); to = scope_Spectrum.toStepping(to); // If parsing the number failed, use the current value. if (to === false || isNaN(to)) { return scope_Locations[handleNumber]; } return to; } // Set the slider value. function valueSet(input, fireSetEvent, exactInput) { var values = asArray(input); var isInit = scope_Locations[0] === undefined; // Event fires by default fireSetEvent = fireSetEvent === undefined ? true : !!fireSetEvent; // Animation is optional. // Make sure the initial values were set before using animated placement. if (options.animate && !isInit) { addClassFor(scope_Target, options.cssClasses.tap, options.animationDuration); } // First pass, without lookAhead but with lookBackward. Values are set from left to right. scope_HandleNumbers.forEach(function (handleNumber) { setHandle(handleNumber, resolveToValue(values[handleNumber], handleNumber), true, false, exactInput); }); var i = scope_HandleNumbers.length === 1 ? 0 : 1; // Secondary passes. Now that all base values are set, apply constraints. // Iterate all handles to ensure constraints are applied for the entire slider (Issue #1009) for (; i < scope_HandleNumbers.length; ++i) { scope_HandleNumbers.forEach(function (handleNumber) { setHandle(handleNumber, scope_Locations[handleNumber], true, true, exactInput); }); } setZindex(); scope_HandleNumbers.forEach(function (handleNumber) { fireEvent("update", handleNumber); // Fire the event only for handles that received a new value, as per #579 if (values[handleNumber] !== null && fireSetEvent) { fireEvent("set", handleNumber); } }); } // Reset slider to initial values function valueReset(fireSetEvent) { valueSet(options.start, fireSetEvent); } // Set value for a single handle function valueSetHandle(handleNumber, value, fireSetEvent, exactInput) { // Ensure numeric input handleNumber = Number(handleNumber); if (!(handleNumber >= 0 && handleNumber < scope_HandleNumbers.length)) { throw new Error("noUiSlider (" + VERSION + "): invalid handle number, got: " + handleNumber); } // Look both backward and forward, since we don't want this handle to "push" other handles (#960); // The exactInput argument can be used to ignore slider stepping (#436) setHandle(handleNumber, resolveToValue(value, handleNumber), true, true, exactInput); fireEvent("update", handleNumber); if (fireSetEvent) { fireEvent("set", handleNumber); } } // Get the slider value. function valueGet() { var values = scope_Values.map(options.format.to); // If only one handle is used, return a single value. if (values.length === 1) { return values[0]; } return values; } // Removes classes from the root and empties it. function destroy() { // remove protected internal listeners removeEvent(INTERNAL_EVENT_NS.aria); removeEvent(INTERNAL_EVENT_NS.tooltips); for (var key in options.cssClasses) { if (!options.cssClasses.hasOwnProperty(key)) { continue; } removeClass(scope_Target, options.cssClasses[key]); } while (scope_Target.firstChild) { scope_Target.removeChild(scope_Target.firstChild); } delete scope_Target.noUiSlider; } function getNextStepsForHandle(handleNumber) { var location = scope_Locations[handleNumber]; var nearbySteps = scope_Spectrum.getNearbySteps(location); var value = scope_Values[handleNumber]; var increment = nearbySteps.thisStep.step; var decrement = null; // If snapped, directly use defined step value if (options.snap) { return [value - nearbySteps.stepBefore.startValue || null, nearbySteps.stepAfter.startValue - value || null]; } // If the next value in this step moves into the next step, // the increment is the start of the next step - the current value if (increment !== false) { if (value + increment > nearbySteps.stepAfter.startValue) { increment = nearbySteps.stepAfter.startValue - value; } } // If the value is beyond the starting point if (value > nearbySteps.thisStep.startValue) { decrement = nearbySteps.thisStep.step; } else if (nearbySteps.stepBefore.step === false) { decrement = false; } // If a handle is at the start of a step, it always steps back into the previous step first else { decrement = value - nearbySteps.stepBefore.highestStep; } // Now, if at the slider edges, there is no in/decrement if (location === 100) { increment = null; } else if (location === 0) { decrement = null; } // As per #391, the comparison for the decrement step can have some rounding issues. var stepDecimals = scope_Spectrum.countStepDecimals(); // Round per #391 if (increment !== null && increment !== false) { increment = Number(increment.toFixed(stepDecimals)); } if (decrement !== null && decrement !== false) { decrement = Number(decrement.toFixed(stepDecimals)); } return [decrement, increment]; } // Get the current step size for the slider. function getNextSteps() { return scope_HandleNumbers.map(getNextStepsForHandle); } // Updateable: margin, limit, padding, step, range, animate, snap function updateOptions(optionsToUpdate, fireSetEvent) { // Spectrum is created using the range, snap, direction and step options. // 'snap' and 'step' can be updated. // If 'snap' and 'step' are not passed, they should remain unchanged. var v = valueGet(); var updateAble = ["margin", "limit", "padding", "range", "animate", "snap", "step", "format", "pips", "tooltips"]; // Only change options that we're actually passed to update. updateAble.forEach(function (name) { // Check for undefined. null removes the value. if (optionsToUpdate[name] !== undefined) { originalOptions[name] = optionsToUpdate[name]; } }); var newOptions = testOptions(originalOptions); // Load new options into the slider state updateAble.forEach(function (name) { if (optionsToUpdate[name] !== undefined) { options[name] = newOptions[name]; } }); scope_Spectrum = newOptions.spectrum; // Limit, margin and padding depend on the spectrum but are stored outside of it. (#677) options.margin = newOptions.margin; options.limit = newOptions.limit; options.padding = newOptions.padding; // Update pips, removes existing. if (options.pips) { pips(options.pips); } else { removePips(); } // Update tooltips, removes existing. if (options.tooltips) { tooltips(); } else { removeTooltips(); } // Invalidate the current positioning so valueSet forces an update. scope_Locations = []; valueSet(isSet(optionsToUpdate.start) ? optionsToUpdate.start : v, fireSetEvent); } // Initialization steps function setupSlider() { // Create the base element, initialize HTML and set classes. // Add handles and connect elements. scope_Base = addSlider(scope_Target); addElements(options.connect, scope_Base); // Attach user events. bindSliderEvents(options.events); // Use the public value method to set the start values. valueSet(options.start); if (options.pips) { pips(options.pips); } if (options.tooltips) { tooltips(); } aria(); } setupSlider(); // noinspection JSUnusedGlobalSymbols scope_Self = { destroy: destroy, steps: getNextSteps, on: bindEvent, off: removeEvent, get: valueGet, set: valueSet, setHandle: valueSetHandle, reset: valueReset, // Exposed for unit testing, don't use this in your application. __moveHandles: function __moveHandles(a, b, c) { moveHandles(a, b, scope_Locations, c); }, options: originalOptions, // Issue #600, #678 updateOptions: updateOptions, target: scope_Target, // Issue #597 removePips: removePips, removeTooltips: removeTooltips, getTooltips: function getTooltips() { return scope_Tooltips; }, getOrigins: function getOrigins() { return scope_Handles; }, pips: pips // Issue #594 }; return scope_Self; } // Run the standard initializer function initialize(target, originalOptions) { if (!target || !target.nodeName) { throw new Error("noUiSlider (" + VERSION + "): create requires a single element, got: " + target); } // Throw an error if the slider was already initialized. if (target.noUiSlider) { throw new Error("noUiSlider (" + VERSION + "): Slider was already initialized."); } // Test the options and create the slider environment; var options = testOptions(originalOptions, target); var api = scope(target, options, originalOptions); target.noUiSlider = api; return api; } // Use an object instead of a function for future expandability; return { // Exposed for unit testing, don't use this in your application. __spectrum: Spectrum, version: VERSION, // A reference to the default classes, allows global changes. // Use the cssClasses option for changes to one slider. cssClasses: cssClasses, create: initialize }; }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /*! * Splide.js * Version : 2.4.20 * License : MIT * Copyright: 2020 Naotoshi Fujita */ /******/(function () { // webpackBootstrap /******/"use strict"; /******/ // The require scope /******/ var __webpack_require__ = {}; /******/ /************************************************************************/ /******/ /* webpack/runtime/define property getters */ /******/!function () { /******/ // define getter functions for harmony exports /******/__webpack_require__.d = function (exports, definition) { /******/for (var key in definition) { /******/if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/!function () { /******/__webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }; /******/ }(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/!function () { /******/ // define __esModule on exports /******/__webpack_require__.r = function (exports) { /******/if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ }(); /******/ /************************************************************************/ // UNUSED EXPORTS: Splide // NAMESPACE OBJECT: ./src/js/constants/states.js var states_namespaceObject = {}; __webpack_require__.r(states_namespaceObject); __webpack_require__.d(states_namespaceObject, { "CREATED": function CREATED() { return _CREATED; }, "DESTROYED": function DESTROYED() { return _DESTROYED; }, "IDLE": function IDLE() { return _IDLE; }, "MOUNTED": function MOUNTED() { return _MOUNTED; }, "MOVING": function MOVING() { return _MOVING; } }); ; // CONCATENATED MODULE: ./src/js/core/event.js /** * The function for providing an Event object simply managing events. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The function for providing an Event object simply managing events. */ /* harmony default export */var core_event = function core_event() { /** * Store all event data. * * @type {Array} */ var data = []; var Event = { /** * Subscribe the given event(s). * * @param {string} events - An event name. Use space to separate multiple events. * Also, namespace is accepted by dot, such as 'resize.{namespace}'. * @param {function} handler - A callback function. * @param {Element} elm - Optional. Native event will be listened to when this arg is provided. * @param {Object} options - Optional. Options for addEventListener. */ on: function on(events, handler, elm, options) { if (elm === void 0) { elm = null; } if (options === void 0) { options = {}; } events.split(' ').forEach(function (event) { if (elm) { elm.addEventListener(event, handler, options); } data.push({ event: event, handler: handler, elm: elm, options: options }); }); }, /** * Unsubscribe the given event(s). * * @param {string} events - A event name or names split by space. * @param {Element} elm - Optional. removeEventListener() will be called when this arg is provided. */ off: function off(events, elm) { if (elm === void 0) { elm = null; } events.split(' ').forEach(function (event) { data = data.filter(function (item) { if (item && item.event === event && item.elm === elm) { unsubscribe(item); return false; } return true; }); }); }, /** * Emit an event. * This method is only for custom events. * * @param {string} event - An event name. * @param {*} args - Any number of arguments passed to handlers. */ emit: function emit(event) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } data.forEach(function (item) { if (!item.elm && item.event.split('.')[0] === event) { item.handler.apply(item, args); } }); }, /** * Clear event data. */ destroy: function destroy() { data.forEach(unsubscribe); data = []; } }; /** * Remove the registered event listener. * * @param {Object} item - An object containing event data. */ function unsubscribe(item) { if (item.elm) { item.elm.removeEventListener(item.event, item.handler, item.options); } } return Event; }; ; // CONCATENATED MODULE: ./src/js/core/state.js /** * The function providing a super simple state system. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The function providing a super simple state system. * * @param {string|number} initialState - Provide the initial state value. */ /* harmony default export */var state = function state(initialState) { /** * Store the current state. * * @type {string|number} */ var curr = initialState; return { /** * Change state. * * @param {string|number} state - A new state. */ set: function set(state) { curr = state; }, /** * Verify if the current state is given one or not. * * @param {string|number} state - A state name to be verified. * * @return {boolean} - True if the current state is the given one. */ is: function is(state) { return state === curr; } }; }; ; // CONCATENATED MODULE: ./src/js/utils/object.js function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i];for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } }return target; };return _extends.apply(this, arguments); } /** * Some utility functions related with Object, supporting IE. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ var keys = Object.keys; /** * Iterate an object like Array.forEach. * IE doesn't support forEach of HTMLCollection. * * @param {Object} obj - An object. * @param {function} callback - A function handling each value. Arguments are value, property and index. */ function each(obj, callback) { keys(obj).some(function (key, index) { return callback(obj[key], key, index); }); } /** * Return values of the given object as an array. * IE doesn't support Object.values. * * @param {Object} obj - An object. * * @return {Array} - An array containing all values of the given object. */ function values(obj) { return keys(obj).map(function (key) { return obj[key]; }); } /** * Check if the given subject is object or not. * * @param {*} subject - A subject to be verified. * * @return {boolean} - True if object, false otherwise. */ function isObject(subject) { return (typeof subject === 'undefined' ? 'undefined' : _typeof(subject)) === 'object'; } /** * Merge two objects deeply. * * @param {Object} to - An object where "from" is merged. * @param {Object} from - An object merged to "to". * * @return {Object} - A merged object. */ function merge(_ref, from) { var to = _extends({}, _ref); each(from, function (value, key) { if (isObject(value)) { if (!isObject(to[key])) { to[key] = {}; } to[key] = merge(to[key], value); } else { to[key] = value; } }); return to; } /** * Assign all properties "from" to "to" object. * * @param {Object} to - An object where properties are assigned. * @param {Object} from - An object whose properties are assigned to "to". * * @return {Object} - An assigned object. */ function object_assign(to, from) { keys(from).forEach(function (key) { if (!to[key]) { Object.defineProperty(to, key, Object.getOwnPropertyDescriptor(from, key)); } }); return to; } ; // CONCATENATED MODULE: ./src/js/utils/utils.js /** * A package of some miscellaneous utility functions. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Convert the given value to array. * * @param {*} value - Any value. * * @return {*[]} - Array containing the given value. */ function toArray(value) { return Array.isArray(value) ? value : [value]; } /** * Check if the given value is between min and max. * Min will be returned when the value is less than min or max will do when greater than max. * * @param {number} value - A number to be checked. * @param {number} m1 - Minimum or maximum number. * @param {number} m2 - Maximum or minimum number. * * @return {number} - A value itself, min or max. */ function between(value, m1, m2) { return Math.min(Math.max(value, m1 > m2 ? m2 : m1), m1 > m2 ? m1 : m2); } /** * The sprintf method with minimum functionality. * * @param {string} format - The string format. * @param {string|Array} replacements - Replacements accepting multiple arguments. * * @returns {string} - Converted string. */ function sprintf(format, replacements) { var i = 0; return format.replace(/%s/g, function () { return toArray(replacements)[i++]; }); } /** * Append px unit to the given subject if necessary. * * @param {number|string} value - A value that may not include an unit. * * @return {string} - If the value is string, return itself. * If number, do value + "px". An empty string, otherwise. */ function unit(value) { var type = typeof value === 'undefined' ? 'undefined' : _typeof(value); if (type === 'number' && value > 0) { return parseFloat(value) + 'px'; } return type === 'string' ? value : ''; } /** * Pad start with 0. * * @param {number} number - A number to be filled with 0. * * @return {string|number} - Padded number. */ function pad(number) { return number < 10 ? '0' + number : number; } /** * Convert the given value to pixel. * * @param {Element} root - Root element where a dummy div is appended. * @param {string|number} value - CSS value to be converted, such as 10rem. * * @return {number} - Pixel. */ function toPixel(root, value) { if (typeof value === 'string') { var div = create('div', {}); applyStyle(div, { position: 'absolute', width: value }); append(root, div); value = div.clientWidth; dom_remove(div); } return +value || 0; } ; // CONCATENATED MODULE: ./src/js/utils/dom.js /** * Some utility functions related with DOM. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Find the first element matching the given selector. * Be aware that all selectors after a space are ignored. * * @param {Element|Node} elm - An ancestor element. * @param {string} selector - DOMString. * * @return {Element|null} - A found element or null. */ function find(elm, selector) { return elm ? elm.querySelector(selector.split(' ')[0]) : null; } /** * Find a first child having the given tag or class name. * * @param {Element} parent - A parent element. * @param {string} tagOrClassName - A tag or class name. * * @return {Element|undefined} - A found element on success or undefined on failure. */ function child(parent, tagOrClassName) { return children(parent, tagOrClassName)[0]; } /** * Return chile elements that matches the provided tag or class name. * * @param {Element} parent - A parent element. * @param {string} tagOrClassName - A tag or class name. * * @return {Element[]} - Found elements. */ function children(parent, tagOrClassName) { if (parent) { return values(parent.children).filter(function (child) { return hasClass(child, tagOrClassName.split(' ')[0]) || child.tagName === tagOrClassName; }); } return []; } /** * Create an element with some optional attributes. * * @param {string} tag - A tag name. * @param {Object} attrs - An object any attribute pairs of name and value. * * @return {Element} - A created element. */ function create(tag, attrs) { var elm = document.createElement(tag); each(attrs, function (value, key) { return setAttribute(elm, key, value); }); return elm; } /** * Convert HTML string to DOM node. * * @param {string} html - HTML string. * * @return {Node} - A created node. */ function domify(html) { var div = create('div', {}); div.innerHTML = html; return div.firstChild; } /** * Remove a given element from a DOM tree. * * @param {Element|Element[]} elms - Element(s) to be removed. */ function dom_remove(elms) { toArray(elms).forEach(function (elm) { if (elm) { var parent = elm.parentElement; parent && parent.removeChild(elm); } }); } /** * Append a child to a given element. * * @param {Element} parent - A parent element. * @param {Element} child - An element to be appended. */ function append(parent, child) { if (parent) { parent.appendChild(child); } } /** * Insert an element before the reference element. * * @param {Element|Node} ref - A reference element. * @param {Element} elm - An element to be inserted. */ function before(elm, ref) { if (elm && ref) { var parent = ref.parentElement; parent && parent.insertBefore(elm, ref); } } /** * Apply styles to the given element. * * @param {Element} elm - An element where styles are applied. * @param {Object} styles - Object containing styles. */ function applyStyle(elm, styles) { if (elm) { each(styles, function (value, prop) { if (value !== null) { elm.style[prop] = value; } }); } } /** * Add or remove classes to/from the element. * This function is for internal usage. * * @param {Element} elm - An element where classes are added. * @param {string|string[]} classes - Class names being added. * @param {boolean} remove - Whether to remove or add classes. */ function addOrRemoveClasses(elm, classes, remove) { if (elm) { toArray(classes).forEach(function (name) { if (name) { elm.classList[remove ? 'remove' : 'add'](name); } }); } } /** * Add classes to the element. * * @param {Element} elm - An element where classes are added. * @param {string|string[]} classes - Class names being added. */ function addClass(elm, classes) { addOrRemoveClasses(elm, classes, false); } /** * Remove a class from the element. * * @param {Element} elm - An element where classes are removed. * @param {string|string[]} classes - A class name being removed. */ function removeClass(elm, classes) { addOrRemoveClasses(elm, classes, true); } /** * Verify if the provided element has the class or not. * * @param {Element} elm - An element. * @param {string} className - A class name. * * @return {boolean} - True if the element has the class or false if not. */ function hasClass(elm, className) { return !!elm && elm.classList.contains(className); } /** * Set attribute to the given element. * * @param {Element} elm - An element where an attribute is assigned. * @param {string} name - Attribute name. * @param {string|number|boolean} value - Attribute value. */ function setAttribute(elm, name, value) { if (elm) { elm.setAttribute(name, value); } } /** * Get attribute from the given element. * * @param {Element} elm - An element where an attribute is assigned. * @param {string} name - Attribute name. * * @return {string} - The value of the given attribute if available. An empty string if not. */ function getAttribute(elm, name) { return elm ? elm.getAttribute(name) : ''; } /** * Remove attribute from the given element. * * @param {Element|Element[]} elms - An element where an attribute is removed. * @param {string|string[]} names - Attribute name. */ function removeAttribute(elms, names) { toArray(names).forEach(function (name) { toArray(elms).forEach(function (elm) { return elm && elm.removeAttribute(name); }); }); } /** * Return the Rect object of the provided object. * * @param {Element} elm - An element. * * @return {ClientRect|DOMRect} - A rect object. */ function getRect(elm) { return elm.getBoundingClientRect(); } /** * Trigger the given callback after all images contained by the element are loaded. * * @param {Element} elm - Element that may contain images. * @param {Function} callback - Callback function fired right after all images are loaded. */ function loaded(elm, callback) { var images = elm.querySelectorAll('img'); var length = images.length; if (length) { var count = 0; each(images, function (img) { img.onload = img.onerror = function () { if (++count === length) { callback(); } }; }); } else { // Trigger the callback immediately if there is no image. callback(); } } ; // CONCATENATED MODULE: ./src/js/constants/types.js /** * Export slider types. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Normal slider. * * @type {string} */ var SLIDE = 'slide'; /** * Loop after the last slide and before the first one. * * @type {string} */ var LOOP = 'loop'; /** * The track doesn't move. * * @type {string} */ var FADE = 'fade'; ; // CONCATENATED MODULE: ./src/js/transitions/slide/index.js /** * The component for general slide effect transition. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for general slide effect transition. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var slide = function slide(Splide, Components) { /** * Hold the list element. * * @type {Element} */ var list; /** * Hold the onEnd callback function. * * @type {function} */ var endCallback; return { /** * Called when the component is mounted. */ mount: function mount() { list = Components.Elements.list; Splide.on('transitionend', function (e) { if (e.target === list && endCallback) { endCallback(); } }, list); }, /** * Start transition. * * @param {number} destIndex - Destination slide index that might be clone's. * @param {number} newIndex - New index. * @param {number} prevIndex - Previous index. * @param {Object} coord - Destination coordinates. * @param {function} done - Callback function must be invoked when transition is completed. */ start: function start(destIndex, newIndex, prevIndex, coord, done) { var options = Splide.options; var edgeIndex = Components.Controller.edgeIndex; var speed = options.speed; endCallback = done; if (Splide.is(SLIDE)) { if (prevIndex === 0 && newIndex >= edgeIndex || prevIndex >= edgeIndex && newIndex === 0) { speed = options.rewindSpeed || speed; } } applyStyle(list, { transition: "transform " + speed + "ms " + options.easing, transform: "translate(" + coord.x + "px," + coord.y + "px)" }); } }; }; ; // CONCATENATED MODULE: ./src/js/transitions/fade/index.js /** * The component for fade transition. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for fade transition. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var fade = function fade(Splide, Components) { var Fade = { /** * Called when the component is mounted. * Apply transition style to the first slide. */ mount: function mount() { apply(Splide.index); }, /** * Start transition. * * @param {number} destIndex - Destination slide index that might be clone's. * @param {number} newIndex - New index. * @param {number} prevIndex - Previous index. * @param {Object} coord - Destination coordinates. * @param {function} done - Callback function must be invoked when transition is completed. */ start: function start(destIndex, newIndex, prevIndex, coord, done) { var track = Components.Elements.track; applyStyle(track, { height: unit(track.clientHeight) }); apply(newIndex); setTimeout(function () { done(); applyStyle(track, { height: '' }); }); } }; /** * Apply transition style to the slide specified by the given index. * * @param {number} index - A slide index. */ function apply(index) { var options = Splide.options; applyStyle(Components.Elements.slides[index], { transition: "opacity " + options.speed + "ms " + options.easing }); } return Fade; }; ; // CONCATENATED MODULE: ./src/js/transitions/index.js /** * Export transition components. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ ; // CONCATENATED MODULE: ./src/js/core/composer.js /** * Provide a function for composing components. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Compose components. * * @param {Splide} Splide - Splide instance. * @param {Object} Components - Additional components. * @param {function} Transition - Change component for transition. * * @return {Object} - An object containing all components. */ function compose(Splide, Components, Transition) { var components = {}; each(Components, function (Component, name) { components[name] = Component(Splide, components, name.toLowerCase()); }); if (!Transition) { Transition = Splide.is(FADE) ? fade : slide; } components.Transition = Transition(Splide, components); return components; } ; // CONCATENATED MODULE: ./src/js/utils/error.js /** * Utility functions for outputting logs. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Prefix of an error massage. * * @type {string} */ var MESSAGE_PREFIX = '[SPLIDE]'; /** * Display an error message on the browser console. * * @param {string} message - An error message. */ function error(message) { console.error(MESSAGE_PREFIX + " " + message); } /** * Check existence of the given object and throw an error if it doesn't. * * @throws {Error} * * @param {*} subject - A subject to be confirmed. * @param {string} message - An error message. */ function exist(subject, message) { if (!subject) { throw new Error(message); } } ; // CONCATENATED MODULE: ./src/js/constants/classes.js /** * Export class names. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * A root class name. * * @type {string} */ var ROOT = 'splide'; /** * The definition table of all classes for elements. * They might be modified by options. * * @type {Object} */ var ELEMENT_CLASSES = { root: ROOT, slider: ROOT + "__slider", track: ROOT + "__track", list: ROOT + "__list", slide: ROOT + "__slide", container: ROOT + "__slide__container", arrows: ROOT + "__arrows", arrow: ROOT + "__arrow", prev: ROOT + "__arrow--prev", next: ROOT + "__arrow--next", pagination: ROOT + "__pagination", page: ROOT + "__pagination__page", clone: ROOT + "__slide--clone", progress: ROOT + "__progress", bar: ROOT + "__progress__bar", autoplay: ROOT + "__autoplay", play: ROOT + "__play", pause: ROOT + "__pause", spinner: ROOT + "__spinner", sr: ROOT + "__sr" }; /** * Definitions of status classes. * * @type {Object} */ var STATUS_CLASSES = { active: 'is-active', visible: 'is-visible', loading: 'is-loading' }; ; // CONCATENATED MODULE: ./src/js/constants/i18n.js /** * Export i18n texts as object. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Texts for i18n. * * @type {Object} */ var I18N = { prev: 'Previous slide', next: 'Next slide', first: 'Go to first slide', last: 'Go to last slide', slideX: 'Go to slide %s', pageX: 'Go to page %s', play: 'Start autoplay', pause: 'Pause autoplay' }; ; // CONCATENATED MODULE: ./src/js/constants/defaults.js /** * Export default options. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ var DEFAULTS = { /** * Determine a slider type. * - 'slide': Regular slider. * - 'loop' : Carousel slider. * - 'fade' : Change slides with fade transition. perPage, drag options are ignored. * * @type {string} */ type: 'slide', /** * Whether to rewind a slider before the first slide or after the last one. * In "loop" mode, this option is ignored. * * @type {boolean} */ rewind: false, /** * Transition speed in milliseconds. * * @type {number} */ speed: 400, /** * Transition speed on rewind in milliseconds. * * @type {number} */ rewindSpeed: 0, /** * Whether to prevent any actions while a slider is transitioning. * If false, navigation, drag and swipe work while the slider is running. * Even so, it will be forced to wait for transition in some cases in the loop mode to shift a slider. * * @type {boolean} */ waitForTransition: true, /** * Define slider max width. * * @type {number} */ width: 0, /** * Define slider height. * * @type {number} */ height: 0, /** * Fix width of slides. CSS format is allowed such as 10em, 80% or 80vw. * perPage number will be ignored when this option is falsy. * * @type {number|string} */ fixedWidth: 0, /** * Fix height of slides. CSS format is allowed such as 10em, 80vh but % unit is not accepted. * heightRatio option will be ignored when this option is falsy. * * @type {number|string} */ fixedHeight: 0, /** * Determine height of slides by ratio to a slider width. * This will be ignored when the fixedHeight is provided. * * @type {number} */ heightRatio: 0, /** * If true, slide width will be determined by the element width itself. * - perPage/perMove should be 1. * * @type {boolean} */ autoWidth: false, /** * If true, slide height will be determined by the element width itself. * - perPage/perMove should be 1. * * @type {boolean} */ autoHeight: false, /** * Determine how many slides should be displayed per page. * * @type {number} */ perPage: 1, /** * Determine how many slides should be moved when a slider goes to next or perv. * * @type {number} */ perMove: 0, /** * Determine manually how many clones should be generated on the left and right side. * The total number of clones will be twice of this number. * * @type {number} */ clones: 0, /** * Start index. * * @type {number} */ start: 0, /** * Determine which slide should be focused if there are multiple slides in a page. * A string "center" is acceptable for centering slides. * * @type {boolean|number|string} */ focus: false, /** * Gap between slides. CSS format is allowed such as 1em. * * @type {number|string} */ gap: 0, /** * Set padding-left/right in horizontal mode or padding-top/bottom in vertical one. * Give a single value to set a same size for both sides or * do an object for different sizes. * Also, CSS format is allowed such as 1em. * * @example * - 10: Number * - '1em': CSS format. * - { left: 0, right: 20 }: Object for different sizes in horizontal mode. * - { top: 0, bottom: 20 }: Object for different sizes in vertical mode. * * @type {number|string|Object} */ padding: 0, /** * Whether to append arrows. * * @type {boolean} */ arrows: true, /** * Change the arrow SVG path like 'm7.61 0.807-2.12...'. * * @type {string} */ arrowPath: '', /** * Whether to append pagination(indicator dots) or not. * * @type {boolean} */ pagination: true, /** * Activate autoplay. * * @type {boolean} */ autoplay: false, /** * Autoplay interval in milliseconds. * * @type {number} */ interval: 5000, /** * Whether to stop autoplay when a slider is hovered. * * @type {boolean} */ pauseOnHover: true, /** * Whether to stop autoplay when a slider elements are focused. * True is recommended for accessibility. * * @type {boolean} */ pauseOnFocus: true, /** * Whether to reset progress of the autoplay timer when resumed. * * @type {boolean} */ resetProgress: true, /** * Loading images lazily. * Image src must be provided by a data-splide-lazy attribute. * * - false: Do nothing. * - 'nearby': Only images around an active slide will be loaded. * - 'sequential': All images will be sequentially loaded. * * @type {boolean|string} */ lazyLoad: false, /** * This option works only when a lazyLoad option is "nearby". * Determine how many pages(not slides) around an active slide should be loaded beforehand. * * @type {number} */ preloadPages: 1, /** * Easing for CSS transition. For example, linear, ease or cubic-bezier(). * * @type {string} */ easing: 'cubic-bezier(.42,.65,.27,.99)', /** * Whether to enable keyboard shortcuts * - true or 'global': Listen to keydown event of the document. * - 'focused': Listen to the keydown event of the slider root element. tabindex="0" will be added to the element. * - false: Disable keyboard shortcuts. * * @type {boolean|string} */ keyboard: 'global', /** * Whether to allow mouse drag and touch swipe. * * @type {boolean} */ drag: true, /** * The angle threshold for drag. * The slider starts moving only when the drag angle is less than this threshold. * * @type {number} */ dragAngleThreshold: 30, /** * Distance threshold for determining if the action is "flick" or "swipe". * When a drag distance is over this value, the action will be treated as "swipe", not "flick". * * @type {number} */ swipeDistanceThreshold: 150, /** * Velocity threshold for determining if the action is "flick" or "swipe". * Around 0.5 is recommended. * * @type {number} */ flickVelocityThreshold: .6, /** * Determine power of flick. The larger number this is, the farther a slider runs by flick. * Around 500 is recommended. * * @type {number} */ flickPower: 600, /** * Limit a number of pages to move by flick. * * @type {number} */ flickMaxPages: 1, /** * Slider direction. * - 'ltr': Left to right. * - 'rtl': Right to left. * - 'ttb': Top to bottom. * * @type {string} */ direction: 'ltr', /** * Set img src to background-image of its parent element. * Images with various sizes can be displayed as same dimension without cropping work. * fixedHeight or heightRatio is required. * * @type {boolean} */ cover: false, /** * Whether to enable accessibility(aria and screen reader texts) or not. * * @type {boolean} */ accessibility: true, /** * Whether to add tabindex="0" to visible slides or not. * * @type {boolean} */ slideFocus: true, /** * Determine if a slider is navigation for another. * Use "sync" API to synchronize two sliders. * * @type {boolean} */ isNavigation: false, /** * Whether to trim spaces before the fist slide or after the last one when "focus" is not 0. * * @type {boolean} */ trimSpace: true, /** * The "is-active" class is added after transition as default. * If true, it will be added before move. * * @type {boolean} */ updateOnMove: false, /** * Throttle duration in milliseconds for the resize event. * * @type {number} */ throttle: 100, /** * Whether to destroy a slider or not. * * @type {boolean} */ destroy: false, /** * Options for specific breakpoints. * * @example * { * 1000: { * perPage: 3, * gap: 20 * }, * 600: { * perPage: 1, * gap: 5, * } * } * * @type {boolean|Object} */ breakpoints: false, /** * Collection of class names. * * @see ./classes.js * * @type {Object} */ classes: ELEMENT_CLASSES, /** * Collection of i18n texts. * * @see ./i18n.js * * @type {Object} */ i18n: I18N }; ; // CONCATENATED MODULE: ./src/js/constants/states.js /** * Export state constants. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Splide has been just created. * * @type {number} */ var _CREATED = 1; /** * All components have been mounted and initialized. * * @type {number} */ var _MOUNTED = 2; /** * Splide is ready for transition. * * @type {number} */ var _IDLE = 3; /** * Splide is moving. * * @type {number} */ var _MOVING = 4; /** * Splide is moving. * * @type {number} */ var _DESTROYED = 5; ; // CONCATENATED MODULE: ./src/js/splide.js function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps);if (staticProps) _defineProperties(Constructor, staticProps);return Constructor; } /** * The main class for applying Splide to an element. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The main class for applying Splide to an element, * providing some APIs to control the behavior. */ var Splide = /*#__PURE__*/function () { /** * Splide constructor. * * @throws {Error} When the given root element or selector is invalid. * * @param {Element|string} root - A selector for a root element or an element itself. * @param {Object} options - Optional. Options to change default behaviour. * @param {Object} Components - Optional. Components. */ function Splide(root, options, Components) { if (options === void 0) { options = {}; } if (Components === void 0) { Components = {}; } this.root = root instanceof Element ? root : document.querySelector(root); exist(this.root, 'An invalid element/selector was given.'); this.Components = null; this.Event = core_event(); this.State = state(_CREATED); this.STATES = states_namespaceObject; this._o = merge(DEFAULTS, options); this._i = 0; this._c = Components; this._e = {}; // Extensions this._t = null; // Transition } /** * Compose and mount components. * * @param {Object} Extensions - Optional. Additional components. * @param {function} Transition - Optional. Set a custom transition component. * * @return {Splide|undefined} - This instance or undefined if an exception occurred. */ var _proto = Splide.prototype; _proto.mount = function mount(Extensions, Transition) { var _this = this; if (Extensions === void 0) { Extensions = this._e; } if (Transition === void 0) { Transition = this._t; } // Reset the state. this.State.set(_CREATED); this._e = Extensions; this._t = Transition; this.Components = compose(this, merge(this._c, Extensions), Transition); try { each(this.Components, function (component, key) { var required = component.required; if (required === undefined || required) { component.mount && component.mount(); } else { delete _this.Components[key]; } }); } catch (e) { error(e.message); return; } var State = this.State; State.set(_MOUNTED); each(this.Components, function (component) { component.mounted && component.mounted(); }); this.emit('mounted'); State.set(_IDLE); this.emit('ready'); applyStyle(this.root, { visibility: 'visible' }); this.on('move drag', function () { return State.set(_MOVING); }).on('moved dragged', function () { return State.set(_IDLE); }); return this; } /** * Set sync target. * * @param {Splide} splide - A Splide instance. * * @return {Splide} - This instance. */ ; _proto.sync = function sync(splide) { this.sibling = splide; return this; } /** * Register callback fired on the given event(s). * * @param {string} events - An event name. Use space to separate multiple events. * Also, namespace is accepted by dot, such as 'resize.{namespace}'. * @param {function} handler - A callback function. * @param {Element} elm - Optional. Native event will be listened to when this arg is provided. * @param {Object} options - Optional. Options for addEventListener. * * @return {Splide} - This instance. */ ; _proto.on = function on(events, handler, elm, options) { if (elm === void 0) { elm = null; } if (options === void 0) { options = {}; } this.Event.on(events, handler, elm, options); return this; } /** * Unsubscribe the given event. * * @param {string} events - A event name. * @param {Element} elm - Optional. removeEventListener() will be called when this arg is provided. * * @return {Splide} - This instance. */ ; _proto.off = function off(events, elm) { if (elm === void 0) { elm = null; } this.Event.off(events, elm); return this; } /** * Emit an event. * * @param {string} event - An event name. * @param {*} args - Any number of arguments passed to handlers. */ ; _proto.emit = function emit(event) { var _this$Event; for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } (_this$Event = this.Event).emit.apply(_this$Event, [event].concat(args)); return this; } /** * Go to the slide specified by the given control. * * @param {string|number} control - A control pattern. * @param {boolean} wait - Optional. Whether to wait for transition. */ ; _proto.go = function go(control, wait) { if (wait === void 0) { wait = this.options.waitForTransition; } if (this.State.is(_IDLE) || this.State.is(_MOVING) && !wait) { this.Components.Controller.go(control, false); } return this; } /** * Verify whether the slider type is the given one or not. * * @param {string} type - A slider type. * * @return {boolean} - True if the slider type is the provided type or false if not. */ ; _proto.is = function is(type) { return type === this._o.type; } /** * Insert a slide. * * @param {Element|string} slide - A slide element to be added. * @param {number} index - A slide will be added at the position. */ ; _proto.add = function add(slide, index) { if (index === void 0) { index = -1; } this.Components.Elements.add(slide, index, this.refresh.bind(this)); return this; } /** * Remove the slide designated by the index. * * @param {number} index - A slide index. */ ; _proto.remove = function remove(index) { this.Components.Elements.remove(index); this.refresh(); return this; } /** * Destroy all Slide objects and clones and recreate them again. */ ; _proto.refresh = function refresh() { this.emit('refresh:before').emit('refresh').emit('resize'); return this; } /** * Destroy the Splide. * "Completely" boolean is mainly for breakpoints. * * @param {boolean} completely - Destroy completely. */ ; _proto.destroy = function destroy(completely) { var _this2 = this; if (completely === void 0) { completely = true; } // Postpone destroy because it should be done after mount. if (this.State.is(_CREATED)) { this.on('ready', function () { return _this2.destroy(completely); }); return; } values(this.Components).reverse().forEach(function (component) { component.destroy && component.destroy(completely); }); this.emit('destroy', completely); // Destroy all event handlers, including ones for native events. this.Event.destroy(); this.State.set(_DESTROYED); return this; } /** * Return the current slide index. * * @return {number} - The current slide index. // */ ; _createClass(Splide, [{ key: "index", get: function get() { return this._i; } /** * Set the current slide index. * * @param {number|string} index - A new index. */ , set: function set(index) { this._i = parseInt(index); } /** * Return length of slides. * This is an alias of Elements.length. * * @return {number} - A number of slides. */ }, { key: "length", get: function get() { return this.Components.Elements.length; } /** * Return options. * * @return {Object} - Options object. */ }, { key: "options", get: function get() { return this._o; } /** * Set options with merging the given object to the current one. * * @param {Object} options - New options. */ , set: function set(options) { var created = this.State.is(_CREATED); if (!created) { this.emit('update'); } this._o = merge(this._o, options); if (!created) { this.emit('updated', this._o); } } /** * Return the class list. * This is an alias of Splide.options.classList. * * @return {Object} - An object containing all class list. */ }, { key: "classes", get: function get() { return this._o.classes; } /** * Return the i18n strings. * This is an alias of Splide.options.i18n. * * @return {Object} - An object containing all i18n strings. */ }, { key: "i18n", get: function get() { return this._o.i18n; } }]); return Splide; }(); ; // CONCATENATED MODULE: ./src/js/components/options/index.js /** * The component for initializing options. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for initializing options. * * @param {Splide} Splide - A Splide instance. * * @return {Object} - The component object. */ /* harmony default export */var options = function options(Splide) { /** * Retrieve options from the data attribute. * Note that IE10 doesn't support dataset property. * * @type {string} */ var options = getAttribute(Splide.root, 'data-splide'); if (options) { try { Splide.options = JSON.parse(options); } catch (e) { error(e.message); } } return { /** * Called when the component is mounted. */ mount: function mount() { if (Splide.State.is(_CREATED)) { Splide.index = Splide.options.start; } } }; }; ; // CONCATENATED MODULE: ./src/js/constants/directions.js /** * Export layout modes. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Enumerate slides from left to right. * * @type {string} */ var LTR = 'ltr'; /** * Enumerate slides from right to left. * * @type {string} */ var RTL = 'rtl'; /** * Enumerate slides in a col. * * @type {string} */ var TTB = 'ttb'; ; // CONCATENATED MODULE: ./src/js/components/elements/slide.js /** * The sub component for handling each slide. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Events for restoring original styles. * * @type {string} */ var STYLE_RESTORE_EVENTS = 'update.slide'; /** * The sub component for handling each slide. * * @param {Splide} Splide - A Splide instance. * @param {number} index - An unique slide index. * @param {number} realIndex - Clones should pass a real slide index. * @param {Element} slide - A slide element. * * @return {Object} - The sub component object. */ /* harmony default export */var elements_slide = function elements_slide(Splide, index, realIndex, slide) { /** * Whether to update "is-active" class before or after transition. * * @type {boolean} */ var updateOnMove = Splide.options.updateOnMove; /** * Events when the slide status is updated. * Append a namespace to remove listeners later. * * @type {string} */ var STATUS_UPDATE_EVENTS = 'ready.slide updated.slide resized.slide moved.slide' + (updateOnMove ? ' move.slide' : ''); /** * Slide sub component object. * * @type {Object} */ var Slide = { /** * Slide element. * * @type {Element} */ slide: slide, /** * Slide index. * * @type {number} */ index: index, /** * Real index for clones. * * @type {number} */ realIndex: realIndex, /** * Container element if available. * * @type {Element|undefined} */ container: child(slide, Splide.classes.container), /** * Whether this is a cloned slide or not. * * @type {boolean} */ isClone: realIndex > -1, /** * Called when the component is mounted. */ mount: function mount() { var _this = this; if (!this.isClone) { slide.id = Splide.root.id + "-slide" + pad(index + 1); } Splide.on(STATUS_UPDATE_EVENTS, function () { return _this.update(); }).on(STYLE_RESTORE_EVENTS, restoreStyles).on('click', function () { return Splide.emit('click', _this); }, slide); /* * Add "is-active" class to a clone element temporarily * and it will be removed on "moved" event. */ if (updateOnMove) { Splide.on('move.slide', function (newIndex) { if (newIndex === realIndex) { _update(true, false); } }); } // Make sure the slide is shown. applyStyle(slide, { display: '' }); // Hold the original styles. this.styles = getAttribute(slide, 'style') || ''; }, /** * Destroy. */ destroy: function destroy() { Splide.off(STATUS_UPDATE_EVENTS).off(STYLE_RESTORE_EVENTS).off('click', slide); removeClass(slide, values(STATUS_CLASSES)); restoreStyles(); removeAttribute(this.container, 'style'); }, /** * Update active and visible status. */ update: function update() { _update(this.isActive(), false); _update(this.isVisible(), true); }, /** * Check whether this slide is active or not. * * @return {boolean} - True if the slide is active or false if not. */ isActive: function isActive() { return Splide.index === index; }, /** * Check whether this slide is visible in the viewport or not. * * @return {boolean} - True if the slide is visible or false if not. */ isVisible: function isVisible() { var active = this.isActive(); if (Splide.is(FADE) || active) { return active; } var ceil = Math.ceil; var trackRect = getRect(Splide.Components.Elements.track); var slideRect = getRect(slide); if (Splide.options.direction === TTB) { return trackRect.top <= slideRect.top && slideRect.bottom <= ceil(trackRect.bottom); } return trackRect.left <= slideRect.left && slideRect.right <= ceil(trackRect.right); }, /** * Calculate how far this slide is from another slide and * return true if the distance is within the given number. * * @param {number} from - Index of a target slide. * @param {number} within - True if the slide is within this number. * * @return {boolean} - True if the slide is within the number or false otherwise. */ isWithin: function isWithin(from, within) { var diff = Math.abs(from - index); if (!Splide.is(SLIDE) && !this.isClone) { diff = Math.min(diff, Splide.length - diff); } return diff < within; } }; /** * Update classes for activity or visibility. * * @param {boolean} active - Is active/visible or not. * @param {boolean} forVisibility - Toggle classes for activity or visibility. */ function _update(active, forVisibility) { var type = forVisibility ? 'visible' : 'active'; var className = STATUS_CLASSES[type]; if (active) { addClass(slide, className); Splide.emit("" + type, Slide); } else { if (hasClass(slide, className)) { removeClass(slide, className); Splide.emit("" + (forVisibility ? 'hidden' : 'inactive'), Slide); } } } /** * Restore the original styles. */ function restoreStyles() { setAttribute(slide, 'style', Slide.styles); } return Slide; }; ; // CONCATENATED MODULE: ./src/js/components/elements/index.js /** * The component for main elements. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The property name for UID stored in a window object. * * @type {string} */ var UID_NAME = 'uid'; /** * The component for main elements. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var components_elements = function components_elements(Splide, Components) { /** * Hold the root element. * * @type {Element} */ var root = Splide.root; /** * Hold the class list. * * @type {Object} */ var classes = Splide.classes; /** * Store Slide objects. * * @type {Array} */ var Slides = []; /* * Assign unique ID to the root element if it doesn't have the one. * Note that IE doesn't support padStart() to fill the uid by 0. */ if (!root.id) { window.splide = window.splide || {}; var uid = window.splide[UID_NAME] || 0; window.splide[UID_NAME] = ++uid; root.id = "splide" + pad(uid); } /** * Elements component object. * * @type {Object} */ var Elements = { /** * Called when the component is mounted. * Collect main elements and store them as member properties. */ mount: function mount() { var _this = this; this.init(); Splide.on('refresh', function () { _this.destroy(); _this.init(); }).on('updated', function () { removeClass(root, getClasses()); addClass(root, getClasses()); }); }, /** * Destroy. */ destroy: function destroy() { Slides.forEach(function (Slide) { Slide.destroy(); }); Slides = []; removeClass(root, getClasses()); }, /** * Initialization. */ init: function init() { var _this2 = this; collect(); addClass(root, getClasses()); this.slides.forEach(function (slide, index) { _this2.register(slide, index, -1); }); }, /** * Register a slide to create a Slide object and handle its behavior. * * @param {Element} slide - A slide element. * @param {number} index - A unique index. This can be negative. * @param {number} realIndex - A real index for clones. Set -1 for real slides. */ register: function register(slide, index, realIndex) { var SlideObject = elements_slide(Splide, index, realIndex, slide); SlideObject.mount(); Slides.push(SlideObject); }, /** * Return the Slide object designated by the index. * Note that "find" is not supported by IE. * * @return {Object|undefined} - A Slide object if available. Undefined if not. */ getSlide: function getSlide(index) { return Slides.filter(function (Slide) { return Slide.index === index; })[0]; }, /** * Return all Slide objects. * * @param {boolean} includeClones - Whether to include cloned slides or not. * * @return {Object[]} - Slide objects. */ getSlides: function getSlides(includeClones) { return includeClones ? Slides : Slides.filter(function (Slide) { return !Slide.isClone; }); }, /** * Return Slide objects belonging to the given page. * * @param {number} page - A page number. * * @return {Object[]} - An array containing Slide objects. */ getSlidesByPage: function getSlidesByPage(page) { var idx = Components.Controller.toIndex(page); var options = Splide.options; var max = options.focus !== false ? 1 : options.perPage; return Slides.filter(function (_ref) { var index = _ref.index; return idx <= index && index < idx + max; }); }, /** * Insert a slide to a slider. * Need to refresh Splide after adding a slide. * * @param {Node|string} slide - A slide element to be added. * @param {number} index - A slide will be added at the position. * @param {Function} callback - Called right after the slide is added to the DOM tree. */ add: function add(slide, index, callback) { if (typeof slide === 'string') { slide = domify(slide); } if (slide instanceof Element) { var ref = this.slides[index]; // This will be removed in mount() of a Slide component. applyStyle(slide, { display: 'none' }); if (ref) { before(slide, ref); this.slides.splice(index, 0, slide); } else { append(this.list, slide); this.slides.push(slide); } loaded(slide, function () { callback && callback(slide); }); } }, /** * Remove a slide from a slider. * Need to refresh Splide after removing a slide. * * @param index - Slide index. */ remove: function remove(index) { dom_remove(this.slides.splice(index, 1)[0]); }, /** * Trigger the provided callback for each Slide object. * * @param {Function} callback - A callback function. The first argument will be the Slide object. */ each: function each(callback) { Slides.forEach(callback); }, /** * Return slides length without clones. * * @return {number} - Slide length. */ get length() { return this.slides.length; }, /** * Return "SlideObjects" length including clones. * * @return {number} - Slide length including clones. */ get total() { return Slides.length; } }; /** * Collect elements. */ function collect() { Elements.slider = child(root, classes.slider); Elements.track = find(root, "." + classes.track); Elements.list = child(Elements.track, classes.list); exist(Elements.track && Elements.list, 'Track or list was not found.'); Elements.slides = children(Elements.list, classes.slide); var arrows = findParts(classes.arrows); Elements.arrows = { prev: find(arrows, "." + classes.prev), next: find(arrows, "." + classes.next) }; var autoplay = findParts(classes.autoplay); Elements.bar = find(findParts(classes.progress), "." + classes.bar); Elements.play = find(autoplay, "." + classes.play); Elements.pause = find(autoplay, "." + classes.pause); Elements.track.id = Elements.track.id || root.id + "-track"; Elements.list.id = Elements.list.id || root.id + "-list"; } /** * Return class names for the root element. */ function getClasses() { var rootClass = classes.root; var options = Splide.options; return [rootClass + "--" + options.type, rootClass + "--" + options.direction, options.drag ? rootClass + "--draggable" : '', options.isNavigation ? rootClass + "--nav" : '', STATUS_CLASSES.active]; } /** * Find parts only from children of the root or track. * * @return {Element} - A found element or undefined. */ function findParts(className) { return child(root, className) || child(Elements.slider, className); } return Elements; }; ; // CONCATENATED MODULE: ./src/js/components/controller/index.js /** * The component for controlling the track. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ var floor = Math.floor; /** * The component for controlling the track. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var controller = function controller(Splide, Components) { /** * Store current options. * * @type {Object} */ var options; /** * True if the slide is LOOP mode. * * @type {boolean} */ var isLoop; /** * Controller component object. * * @type {Object} */ var Controller = { /** * Called when the component is mounted. */ mount: function mount() { options = Splide.options; isLoop = Splide.is(LOOP); bind(); }, /** * Make track run by the given control. * - "+{i}" : Increment the slide index by i. * - "-{i}" : Decrement the slide index by i. * - "{i}" : Go to the slide whose index is i. * - ">" : Go to next page. * - "<" : Go to prev page. * - ">{i}" : Go to page i. * * @param {string|number} control - A control pattern. * @param {boolean} silently - Go to the destination without event emission. */ go: function go(control, silently) { var destIndex = this.trim(this.parse(control)); Components.Track.go(destIndex, this.rewind(destIndex), silently); }, /** * Parse the given control and return the destination index for the track. * * @param {string} control - A control target pattern. * * @return {number} - A parsed target. */ parse: function parse(control) { var index = Splide.index; var matches = String(control).match(/([+\-<>]+)(\d+)?/); var indicator = matches ? matches[1] : ''; var number = matches ? parseInt(matches[2]) : 0; switch (indicator) { case '+': index += number || 1; break; case '-': index -= number || 1; break; case '>': case '<': index = parsePage(number, index, indicator === '<'); break; default: index = parseInt(control); } return index; }, /** * Compute index from the given page number. * * @param {number} page - Page number. * * @return {number} - A computed page number. */ toIndex: function toIndex(page) { if (hasFocus()) { return page; } var length = Splide.length; var perPage = options.perPage; var index = page * perPage; index = index - (this.pageLength * perPage - length) * floor(index / length); // Adjustment for the last page. if (length - perPage <= index && index < length) { index = length - perPage; } return index; }, /** * Compute page number from the given slide index. * * @param {number} index - Slide index. * * @return {number} - A computed page number. */ toPage: function toPage(index) { if (hasFocus()) { return index; } var length = Splide.length; var perPage = options.perPage; // Make the last "perPage" number of slides belong to the last page. if (length - perPage <= index && index < length) { return floor((length - 1) / perPage); } return floor(index / perPage); }, /** * Trim the given index according to the current mode. * Index being returned could be less than 0 or greater than the length in Loop mode. * * @param {number} index - An index being trimmed. * * @return {number} - A trimmed index. */ trim: function trim(index) { if (!isLoop) { index = options.rewind ? this.rewind(index) : between(index, 0, this.edgeIndex); } return index; }, /** * Rewind the given index if it's out of range. * * @param {number} index - An index. * * @return {number} - A rewound index. */ rewind: function rewind(index) { var edge = this.edgeIndex; if (isLoop) { while (index > edge) { index -= edge + 1; } while (index < 0) { index += edge + 1; } } else { if (index > edge) { index = 0; } else if (index < 0) { index = edge; } } return index; }, /** * Check if the direction is "rtl" or not. * * @return {boolean} - True if "rtl" or false if not. */ isRtl: function isRtl() { return options.direction === RTL; }, /** * Return the page length. * * @return {number} - Max page number. */ get pageLength() { var length = Splide.length; return hasFocus() ? length : Math.ceil(length / options.perPage); }, /** * Return the edge index. * * @return {number} - Edge index. */ get edgeIndex() { var length = Splide.length; if (!length) { return 0; } if (hasFocus() || options.isNavigation || isLoop) { return length - 1; } return length - options.perPage; }, /** * Return the index of the previous slide. * * @return {number} - The index of the previous slide if available. -1 otherwise. */ get prevIndex() { var prev = Splide.index - 1; if (isLoop || options.rewind) { prev = this.rewind(prev); } return prev > -1 ? prev : -1; }, /** * Return the index of the next slide. * * @return {number} - The index of the next slide if available. -1 otherwise. */ get nextIndex() { var next = Splide.index + 1; if (isLoop || options.rewind) { next = this.rewind(next); } return Splide.index < next && next <= this.edgeIndex || next === 0 ? next : -1; } }; /** * Listen to some events. */ function bind() { Splide.on('move', function (newIndex) { Splide.index = newIndex; }).on('updated refresh', function (newOptions) { options = newOptions || options; Splide.index = between(Splide.index, 0, Controller.edgeIndex); }); } /** * Verify if the focus option is available or not. * * @return {boolean} - True if a slider has the focus option. */ function hasFocus() { return options.focus !== false; } /** * Return the next or previous page index computed by the page number and current index. * * @param {number} number - Specify the page number. * @param {number} index - Current index. * @param {boolean} prev - Prev or next. * * @return {number} - Slide index. */ function parsePage(number, index, prev) { if (number > -1) { return Controller.toIndex(number); } var perMove = options.perMove; var sign = prev ? -1 : 1; if (perMove) { return index + perMove * sign; } return Controller.toIndex(Controller.toPage(index) + sign); } return Controller; }; ; // CONCATENATED MODULE: ./src/js/components/track/index.js /** * The component for moving list in the track. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ var abs = Math.abs; /** * The component for moving list in the track. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var track = function track(Splide, Components) { /** * Hold the Layout component. * * @type {Object} */ var Layout; /** * Hold the Layout component. * * @type {Object} */ var Elements; /** * Store the list element. * * @type {Element} */ var list; /** * Whether the current direction is vertical or not. * * @type {boolean} */ var isVertical = Splide.options.direction === TTB; /** * Whether the slider type is FADE or not. * * @type {boolean} */ var isFade = Splide.is(FADE); /** * Whether the slider direction is RTL or not. * * @type {boolean} */ var isRTL = Splide.options.direction === RTL; /** * This will be true while transitioning from the last index to the first one. * * @type {boolean} */ var isLoopPending = false; /** * Sign for the direction. Only RTL mode uses the positive sign. * * @type {number} */ var sign = isRTL ? 1 : -1; /** * Track component object. * * @type {Object} */ var Track = { /** * Make public the sign defined locally. * * @type {number} */ sign: sign, /** * Called when the component is mounted. */ mount: function mount() { Elements = Components.Elements; Layout = Components.Layout; list = Elements.list; }, /** * Called after the component is mounted. * The resize event must be registered after the Layout's one is done. */ mounted: function mounted() { var _this = this; if (!isFade) { this.jump(0); Splide.on('mounted resize updated', function () { _this.jump(Splide.index); }); } }, /** * Go to the given destination index. * After arriving there, the track is jump to the new index without animation, mainly for loop mode. * * @param {number} destIndex - A destination index. * This can be negative or greater than slides length for reaching clones. * @param {number} newIndex - An actual new index. They are always same in Slide and Rewind mode. * @param {boolean} silently - If true, suppress emitting events. */ go: function go(destIndex, newIndex, silently) { var newPosition = getTrimmedPosition(destIndex); var prevIndex = Splide.index; // Prevent any actions while transitioning from the last index to the first one for jump. if (Splide.State.is(_MOVING) && isLoopPending) { return; } isLoopPending = destIndex !== newIndex; if (!silently) { Splide.emit('move', newIndex, prevIndex, destIndex); } if (Math.abs(newPosition - this.position) >= 1 || isFade) { Components.Transition.start(destIndex, newIndex, prevIndex, this.toCoord(newPosition), function () { onTransitionEnd(destIndex, newIndex, prevIndex, silently); }); } else { if (destIndex !== prevIndex && Splide.options.trimSpace === 'move') { Components.Controller.go(destIndex + destIndex - prevIndex, silently); } else { onTransitionEnd(destIndex, newIndex, prevIndex, silently); } } }, /** * Move the track to the specified index. * * @param {number} index - A destination index where the track jumps. */ jump: function jump(index) { this.translate(getTrimmedPosition(index)); }, /** * Set the list position by CSS translate property. * * @param {number} position - A new position value. */ translate: function translate(position) { applyStyle(list, { transform: "translate" + (isVertical ? 'Y' : 'X') + "(" + position + "px)" }); }, /** * Cancel the transition and set the list position. * Also, loop the slider if necessary. */ cancel: function cancel() { if (Splide.is(LOOP)) { this.shift(); } else { // Ensure the current position. this.translate(this.position); } applyStyle(list, { transition: '' }); }, /** * Shift the slider if it exceeds borders on the edge. */ shift: function shift() { var position = abs(this.position); var left = abs(this.toPosition(0)); var right = abs(this.toPosition(Splide.length)); var innerSize = right - left; if (position < left) { position += innerSize; } else if (position > right) { position -= innerSize; } this.translate(sign * position); }, /** * Trim redundant spaces on the left or right edge if necessary. * * @param {number} position - Position value to be trimmed. * * @return {number} - Trimmed position. */ trim: function trim(position) { if (!Splide.options.trimSpace || Splide.is(LOOP)) { return position; } var edge = sign * (Layout.totalSize() - Layout.size - Layout.gap); return between(position, edge, 0); }, /** * Calculate the closest slide index from the given position. * * @param {number} position - A position converted to an slide index. * * @return {number} - The closest slide index. */ toIndex: function toIndex(position) { var _this2 = this; var index = 0; var minDistance = Infinity; Elements.getSlides(true).forEach(function (Slide) { var slideIndex = Slide.index; var distance = abs(_this2.toPosition(slideIndex) - position); if (distance < minDistance) { minDistance = distance; index = slideIndex; } }); return index; }, /** * Return coordinates object by the given position. * * @param {number} position - A position value. * * @return {Object} - A coordinates object. */ toCoord: function toCoord(position) { return { x: isVertical ? 0 : position, y: isVertical ? position : 0 }; }, /** * Calculate the track position by a slide index. * * @param {number} index - Slide index. * * @return {Object} - Calculated position. */ toPosition: function toPosition(index) { var position = Layout.totalSize(index) - Layout.slideSize(index) - Layout.gap; return sign * (position + this.offset(index)); }, /** * Return the current offset value, considering direction. * * @return {number} - Offset amount. */ offset: function offset(index) { var focus = Splide.options.focus; var slideSize = Layout.slideSize(index); if (focus === 'center') { return -(Layout.size - slideSize) / 2; } return -(parseInt(focus) || 0) * (slideSize + Layout.gap); }, /** * Return the current position. * This returns the correct position even while transitioning by CSS. * * @return {number} - Current position. */ get position() { var prop = isVertical ? 'top' : isRTL ? 'right' : 'left'; return getRect(list)[prop] - (getRect(Elements.track)[prop] - Layout.padding[prop] * sign); } }; /** * Called whenever slides arrive at a destination. * * @param {number} destIndex - A destination index. * @param {number} newIndex - A new index. * @param {number} prevIndex - A previous index. * @param {boolean} silently - If true, suppress emitting events. */ function onTransitionEnd(destIndex, newIndex, prevIndex, silently) { applyStyle(list, { transition: '' }); isLoopPending = false; if (!isFade) { Track.jump(newIndex); } if (!silently) { Splide.emit('moved', newIndex, prevIndex, destIndex); } } /** * Convert index to the trimmed position. * * @return {number} - Trimmed position. */ function getTrimmedPosition(index) { return Track.trim(Track.toPosition(index)); } return Track; }; ; // CONCATENATED MODULE: ./src/js/components/clones/index.js /** * The component for cloning some slides for "loop" mode of the track. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for cloning some slides for "loop" mode of the track. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var clones = function clones(Splide, Components) { /** * Store information of all clones. * * @type {Array} */ var clones = []; /** * Store the current clone count on one side. * * @type {number} */ var cloneCount = 0; /** * Keep Elements component. * * @type {Object} */ var Elements = Components.Elements; /** * Clones component object. * * @type {Object} */ var Clones = { /** * Called when the component is mounted. */ mount: function mount() { var _this = this; if (Splide.is(LOOP)) { init(); Splide.on('refresh:before', function () { _this.destroy(); }).on('refresh', init).on('resize', function () { if (cloneCount !== getCloneCount()) { // Destroy before refresh not to collect clones by the Elements component. _this.destroy(); Splide.refresh(); } }); } }, /** * Destroy. */ destroy: function destroy() { dom_remove(clones); clones = []; }, /** * Return all clones. * * @return {Element[]} - Cloned elements. */ get clones() { return clones; }, /** * Return clone length. * * @return {number} - A length of clones. */ get length() { return clones.length; } }; /** * Initialization. */ function init() { Clones.destroy(); cloneCount = getCloneCount(); generateClones(cloneCount); } /** * Generate and append/prepend clones. * * @param {number} count - The half number of clones. */ function generateClones(count) { var length = Elements.length, register = Elements.register; if (length) { var slides = Elements.slides; while (slides.length < count) { slides = slides.concat(slides); } // Clones after the last element. slides.slice(0, count).forEach(function (elm, index) { var clone = cloneDeeply(elm); append(Elements.list, clone); clones.push(clone); register(clone, index + length, index % length); }); // Clones before the first element. slides.slice(-count).forEach(function (elm, index) { var clone = cloneDeeply(elm); before(clone, slides[0]); clones.push(clone); register(clone, index - count, (length + index - count % length) % length); }); } } /** * Return half count of clones to be generated. * Clone count is determined by: * - "clones" value in the options. * - Number of slides that can be placed in a view in "fixed" mode. * - Max pages a flick action can move. * - Whether the slide length is enough for perPage. * * @return {number} - Count for clones. */ function getCloneCount() { var options = Splide.options; if (options.clones) { return options.clones; } // Use the slide length in autoWidth mode because the number cannot be calculated. var baseCount = options.autoWidth || options.autoHeight ? Elements.length : options.perPage; var dimension = options.direction === TTB ? 'Height' : 'Width'; var fixedSize = toPixel(Splide.root, options["fixed" + dimension]); if (fixedSize) { // Roughly calculate the count. This needs not to be strict. baseCount = Math.ceil(Elements.track["client" + dimension] / fixedSize); } return baseCount * (options.drag ? options.flickMaxPages + 1 : 1); } /** * Clone deeply the given element. * * @param {Element} elm - An element being duplicated. * * @return {Node} - A cloned node(element). */ function cloneDeeply(elm) { var clone = elm.cloneNode(true); addClass(clone, Splide.classes.clone); // ID should not be duplicated. removeAttribute(clone, 'id'); return clone; } return Clones; }; ; // CONCATENATED MODULE: ./src/js/components/layout/directions/horizontal.js /** * The resolver component for horizontal layout. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The resolver component for horizontal layout. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The resolver object. */ /* harmony default export */var horizontal = function horizontal(Splide, Components) { /** * Keep the Elements component. * * @type {string} */ var Elements = Components.Elements; /** * Keep the root element. * * @type {Element} */ var root = Splide.root; /** * Keep the track element. * * @type {Element} */ var track; /** * Keep the latest options. * * @type {Element} */ var options = Splide.options; return { /** * Margin property name. * * @type {string} */ margin: 'margin' + (options.direction === RTL ? 'Left' : 'Right'), /** * Always 0 because the height will be determined by inner contents. * * @type {number} */ height: 0, /** * Initialization. */ init: function init() { this.resize(); }, /** * Resize gap and padding. * This must be called on init. */ resize: function resize() { options = Splide.options; track = Elements.track; this.gap = toPixel(root, options.gap); var padding = options.padding; var left = toPixel(root, padding.left || padding); var right = toPixel(root, padding.right || padding); this.padding = { left: left, right: right }; applyStyle(track, { paddingLeft: unit(left), paddingRight: unit(right) }); }, /** * Return total width from the left of the list to the right of the slide specified by the provided index. * * @param {number} index - Optional. A slide index. If undefined, total width of the slider will be returned. * * @return {number} - Total width to the right side of the specified slide, or 0 for an invalid index. */ totalWidth: function totalWidth(index) { if (index === void 0) { index = Splide.length - 1; } var Slide = Elements.getSlide(index); var width = 0; if (Slide) { var slideRect = getRect(Slide.slide); var listRect = getRect(Elements.list); if (options.direction === RTL) { width = listRect.right - slideRect.left; } else { width = slideRect.right - listRect.left; } width += this.gap; } return width; }, /** * Return the slide width in px. * * @param {number} index - Slide index. * * @return {number} - The slide width. */ slideWidth: function slideWidth(index) { if (options.autoWidth) { var Slide = Elements.getSlide(index); return Slide ? Slide.slide.offsetWidth : 0; } var width = options.fixedWidth || (this.width + this.gap) / options.perPage - this.gap; return toPixel(root, width); }, /** * Return the slide height in px. * * @return {number} - The slide height. */ slideHeight: function slideHeight() { var height = options.height || options.fixedHeight || this.width * options.heightRatio; return toPixel(root, height); }, /** * Return slider width without padding. * * @return {number} - Current slider width. */ get width() { return track.clientWidth - this.padding.left - this.padding.right; } }; }; ; // CONCATENATED MODULE: ./src/js/components/layout/directions/vertical.js /** * The resolver component for vertical layout. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The resolver component for vertical layout. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The resolver object. */ /* harmony default export */var vertical = function vertical(Splide, Components) { /** * Keep the Elements component. * * @type {string} */ var Elements = Components.Elements; /** * Keep the root element. * * @type {Element} */ var root = Splide.root; /** * Keep the track element. * * @type {Element} */ var track; /** * Keep the latest options. * * @type {Element} */ var options; return { /** * Margin property name. * * @type {string} */ margin: 'marginBottom', /** * Initialization. */ init: function init() { this.resize(); }, /** * Resize gap and padding. * This must be called on init. */ resize: function resize() { options = Splide.options; track = Elements.track; this.gap = toPixel(root, options.gap); var padding = options.padding; var top = toPixel(root, padding.top || padding); var bottom = toPixel(root, padding.bottom || padding); this.padding = { top: top, bottom: bottom }; applyStyle(track, { paddingTop: unit(top), paddingBottom: unit(bottom) }); }, /** * Return total height from the top of the list to the bottom of the slide specified by the provided index. * * @param {number} index - Optional. A slide index. If undefined, total height of the slider will be returned. * * @return {number} - Total height to the bottom of the specified slide, or 0 for an invalid index. */ totalHeight: function totalHeight(index) { if (index === void 0) { index = Splide.length - 1; } var Slide = Elements.getSlide(index); if (Slide) { return getRect(Slide.slide).bottom - getRect(Elements.list).top + this.gap; } return 0; }, /** * Return the slide width in px. * * @return {number} - The slide width. */ slideWidth: function slideWidth() { return toPixel(root, options.fixedWidth || this.width); }, /** * Return the slide height in px. * * @param {number} index - Slide index. * * @return {number} - The slide height. */ slideHeight: function slideHeight(index) { if (options.autoHeight) { var Slide = Elements.getSlide(index); return Slide ? Slide.slide.offsetHeight : 0; } var height = options.fixedHeight || (this.height + this.gap) / options.perPage - this.gap; return toPixel(root, height); }, /** * Return slider width without padding. * * @return {number} - Current slider width. */ get width() { return track.clientWidth; }, /** * Return slide height without padding. * * @return {number} - Slider height. */ get height() { var height = options.height || this.width * options.heightRatio; exist(height, '"height" or "heightRatio" is missing.'); return toPixel(root, height) - this.padding.top - this.padding.bottom; } }; }; ; // CONCATENATED MODULE: ./src/js/utils/time.js /** * A package of utility functions related with time. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Simple throttle function that controls how often the given function is executed. * * @param {function} func - A function to be throttled. * @param {number} wait - Time in millisecond for interval of execution. * * @return {Function} - A debounced function. */ function throttle(func, wait) { var timeout; // Declare function by the "function" keyword to prevent "this" from being inherited. return function () { if (!timeout) { timeout = setTimeout(function () { func(); timeout = null; }, wait); } }; } /** * Custom setInterval function that provides progress rate as callback. * * @param {function} callback - A callback function fired every time the interval time passes. * @param {number} interval - Interval duration in milliseconds. * @param {function} progress - A callback function fired whenever the progress goes. * * @return {Object} - An object containing play() and pause() functions. */ function createInterval(callback, interval, progress) { var _window = window, requestAnimationFrame = _window.requestAnimationFrame; var start, elapse, rate, _pause = true; var step = function step(timestamp) { if (!_pause) { if (!start) { start = timestamp; if (rate && rate < 1) { start -= rate * interval; } } elapse = timestamp - start; rate = elapse / interval; if (elapse >= interval) { start = 0; rate = 1; callback(); } if (progress) { progress(rate); } requestAnimationFrame(step); } }; return { pause: function pause() { _pause = true; start = 0; }, play: function play(reset) { start = 0; if (reset) { rate = 0; } if (_pause) { _pause = false; requestAnimationFrame(step); } } }; } ; // CONCATENATED MODULE: ./src/js/components/layout/index.js /** * The component for handing slide layouts and their sizes. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for handing slide layouts and their sizes. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var layout = function layout(Splide, Components) { /** * Keep the Elements component. * * @type {string} */ var Elements = Components.Elements; /** * Whether the slider is vertical or not. * * @type {boolean} */ var isVertical = Splide.options.direction === TTB; /** * Layout component object. * * @type {Object} */ var Layout = object_assign({ /** * Called when the component is mounted. */ mount: function mount() { bind(); init(); // The word "size" means width for a horizontal slider and height for a vertical slider. this.totalSize = isVertical ? this.totalHeight : this.totalWidth; this.slideSize = isVertical ? this.slideHeight : this.slideWidth; }, /** * Destroy the component. */ destroy: function destroy() { removeAttribute([Elements.list, Elements.track], 'style'); }, /** * Return the slider height on the vertical mode or width on the horizontal mode. * * @return {number} */ get size() { return isVertical ? this.height : this.width; } }, isVertical ? vertical(Splide, Components) : horizontal(Splide, Components)); /** * Init slider styles according to options. */ function init() { Layout.init(); applyStyle(Splide.root, { maxWidth: unit(Splide.options.width) }); Elements.each(function (Slide) { Slide.slide.style[Layout.margin] = unit(Layout.gap); }); resize(); } /** * Listen the resize native event with throttle. * Initialize when the component is mounted or options are updated. */ function bind() { Splide.on('resize load', throttle(function () { Splide.emit('resize'); }, Splide.options.throttle), window).on('resize', resize).on('updated refresh', init); } /** * Resize the track and slide elements. */ function resize() { var options = Splide.options; Layout.resize(); applyStyle(Elements.track, { height: unit(Layout.height) }); var slideHeight = options.autoHeight ? null : unit(Layout.slideHeight()); Elements.each(function (Slide) { applyStyle(Slide.container, { height: slideHeight }); applyStyle(Slide.slide, { width: options.autoWidth ? null : unit(Layout.slideWidth(Slide.index)), height: Slide.container ? null : slideHeight }); }); Splide.emit('resized'); } return Layout; }; ; // CONCATENATED MODULE: ./src/js/components/drag/index.js /** * The component for supporting mouse drag and swipe. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ var drag_abs = Math.abs; /** * If the absolute velocity is greater thant this value, * a slider always goes to a different slide after drag, not allowed to stay on a current slide. */ var MIN_VELOCITY = 0.1; /** * Adjust how much the track can be pulled on the first or last page. * The larger number this is, the farther the track moves. * This should be around 5 - 9. * * @type {number} */ var FRICTION_REDUCER = 7; /** * The component supporting mouse drag and swipe. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var drag = function drag(Splide, Components) { /** * Store the Move component. * * @type {Object} */ var Track = Components.Track; /** * Store the Controller component. * * @type {Object} */ var Controller = Components.Controller; /** * Coordinate of the track on starting drag. * * @type {Object} */ var startCoord; /** * Analyzed info on starting drag. * * @type {Object|null} */ var startInfo; /** * Analyzed info being updated while dragging/swiping. * * @type {Object} */ var currentInfo; /** * Determine whether slides are being dragged or not. * * @type {boolean} */ var isDragging; /** * Whether the slider direction is vertical or not. * * @type {boolean} */ var isVertical = Splide.options.direction === TTB; /** * Axis for the direction. * * @type {string} */ var axis = isVertical ? 'y' : 'x'; /** * Drag component object. * * @type {Object} */ var Drag = { /** * Whether dragging is disabled or not. * * @type {boolean} */ disabled: false, /** * Called when the component is mounted. */ mount: function mount() { var _this = this; var Elements = Components.Elements; var track = Elements.track; Splide.on('touchstart mousedown', start, track).on('touchmove mousemove', move, track, { passive: false }).on('touchend touchcancel mouseleave mouseup dragend', end, track).on('mounted refresh', function () { // Prevent dragging an image or anchor itself. each(Elements.list.querySelectorAll('img, a'), function (elm) { Splide.off('dragstart', elm).on('dragstart', function (e) { e.preventDefault(); }, elm, { passive: false }); }); }).on('mounted updated', function () { _this.disabled = !Splide.options.drag; }); } }; /** * Called when the track starts to be dragged. * * @param {TouchEvent|MouseEvent} e - TouchEvent or MouseEvent object. */ function start(e) { if (!Drag.disabled && !isDragging) { // These prams are used to evaluate whether the slider should start moving. init(e); } } /** * Initialize parameters. * * @param {TouchEvent|MouseEvent} e - TouchEvent or MouseEvent object. */ function init(e) { startCoord = Track.toCoord(Track.position); startInfo = analyze(e, {}); currentInfo = startInfo; } /** * Called while the track being dragged. * * @param {TouchEvent|MouseEvent} e - TouchEvent or MouseEvent object. */ function move(e) { if (startInfo) { currentInfo = analyze(e, startInfo); if (isDragging) { if (e.cancelable) { e.preventDefault(); } if (!Splide.is(FADE)) { var position = startCoord[axis] + currentInfo.offset[axis]; Track.translate(resist(position)); } } else { if (shouldMove(currentInfo)) { Splide.emit('drag', startInfo); isDragging = true; Track.cancel(); // These params are actual drag data. init(e); } } } } /** * Determine whether to start moving the track or not by drag angle. * * @param {Object} info - An information object. * * @return {boolean} - True if the track should be moved or false if not. */ function shouldMove(_ref) { var offset = _ref.offset; if (Splide.State.is(_MOVING) && Splide.options.waitForTransition) { return false; } var angle = Math.atan(drag_abs(offset.y) / drag_abs(offset.x)) * 180 / Math.PI; if (isVertical) { angle = 90 - angle; } return angle < Splide.options.dragAngleThreshold; } /** * Resist dragging the track on the first/last page because there is no more. * * @param {number} position - A position being applied to the track. * * @return {Object} - Adjusted position. */ function resist(position) { if (Splide.is(SLIDE)) { var sign = Track.sign; var _start = sign * Track.trim(Track.toPosition(0)); var _end = sign * Track.trim(Track.toPosition(Controller.edgeIndex)); position *= sign; if (position < _start) { position = _start - FRICTION_REDUCER * Math.log(_start - position); } else if (position > _end) { position = _end + FRICTION_REDUCER * Math.log(position - _end); } position *= sign; } return position; } /** * Called when dragging ends. */ function end() { startInfo = null; if (isDragging) { Splide.emit('dragged', currentInfo); go(currentInfo); isDragging = false; } } /** * Go to the slide determined by the analyzed data. * * @param {Object} info - An info object. */ function go(info) { var velocity = info.velocity[axis]; var absV = drag_abs(velocity); if (absV > 0) { var options = Splide.options; var index = Splide.index; var sign = velocity < 0 ? -1 : 1; var destIndex = index; if (!Splide.is(FADE)) { var destination = Track.position; if (absV > options.flickVelocityThreshold && drag_abs(info.offset[axis]) < options.swipeDistanceThreshold) { destination += sign * Math.min(absV * options.flickPower, Components.Layout.size * (options.flickMaxPages || 1)); } destIndex = Track.toIndex(destination); } /* * Do not allow the track to go to a previous position if there is enough velocity. * Always use the adjacent index for the fade mode. */ if (destIndex === index && absV > MIN_VELOCITY) { destIndex = index + sign * Track.sign; } if (Splide.is(SLIDE)) { destIndex = between(destIndex, 0, Controller.edgeIndex); } Controller.go(destIndex, options.isNavigation); } } /** * Analyze the given event object and return important information for handling swipe behavior. * * @param {Event} e - Touch or Mouse event object. * @param {Object} startInfo - Information analyzed on start for calculating difference from the current one. * * @return {Object} - An object containing analyzed information, such as offset, velocity, etc. */ function analyze(e, startInfo) { var timeStamp = e.timeStamp, touches = e.touches; var _ref2 = touches ? touches[0] : e, clientX = _ref2.clientX, clientY = _ref2.clientY; var _ref3 = startInfo.to || {}, _ref3$x = _ref3.x, fromX = _ref3$x === void 0 ? clientX : _ref3$x, _ref3$y = _ref3.y, fromY = _ref3$y === void 0 ? clientY : _ref3$y; var startTime = startInfo.time || 0; var offset = { x: clientX - fromX, y: clientY - fromY }; var duration = timeStamp - startTime; var velocity = { x: offset.x / duration, y: offset.y / duration }; return { to: { x: clientX, y: clientY }, offset: offset, time: timeStamp, velocity: velocity }; } return Drag; }; ; // CONCATENATED MODULE: ./src/js/components/click/index.js /** * The component for handling a click event. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for handling a click event. * Click should be disabled during drag/swipe. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var click = function click(Splide, Components) { /** * Whether click is disabled or not. * * @type {boolean} */ var disabled = false; /** * Click component object. * * @type {Object} */ var Click = { /** * Mount only when the drag is activated and the slide type is not "fade". * * @type {boolean} */ required: Splide.options.drag, /** * Called when the component is mounted. */ mount: function mount() { Splide.on('click', onClick, Components.Elements.track, { capture: true }).on('drag', function () { disabled = true; }).on('dragged', function () { // Make sure the flag is released after the click event is fired. setTimeout(function () { disabled = false; }); }); } }; /** * Called when a track element is clicked. * * @param {Event} e - A click event. */ function onClick(e) { if (disabled) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); } } return Click; }; ; // CONCATENATED MODULE: ./src/js/components/autoplay/index.js /** * The component for playing slides automatically. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Set of pause flags. */ var PAUSE_FLAGS = { HOVER: 1, FOCUS: 2, MANUAL: 3 }; /** * The component for playing slides automatically. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * @param {string} name - A component name as a lowercase string. * * @return {Object} - The component object. */ /* harmony default export */var autoplay = function autoplay(Splide, Components, name) { /** * Store pause flags. * * @type {Array} */ var flags = []; /** * Store an interval object. * * @type {Object}; */ var interval; /** * Keep the Elements component. * * @type {string} */ var Elements = Components.Elements; /** * Autoplay component object. * * @type {Object} */ var Autoplay = { /** * Required only when the autoplay option is true. * * @type {boolean} */ required: Splide.options.autoplay, /** * Called when the component is mounted. * Note that autoplay starts only if there are slides over perPage number. */ mount: function mount() { var options = Splide.options; if (Elements.slides.length > options.perPage) { interval = createInterval(function () { Splide.go('>'); }, options.interval, function (rate) { Splide.emit(name + ":playing", rate); if (Elements.bar) { applyStyle(Elements.bar, { width: rate * 100 + "%" }); } }); bind(); this.play(); } }, /** * Start autoplay. * * @param {number} flag - A pause flag to be removed. */ play: function play(flag) { if (flag === void 0) { flag = 0; } flags = flags.filter(function (f) { return f !== flag; }); if (!flags.length) { Splide.emit(name + ":play"); interval.play(Splide.options.resetProgress); } }, /** * Pause autoplay. * Note that Array.includes is not supported by IE. * * @param {number} flag - A pause flag to be added. */ pause: function pause(flag) { if (flag === void 0) { flag = 0; } interval.pause(); if (flags.indexOf(flag) === -1) { flags.push(flag); } if (flags.length === 1) { Splide.emit(name + ":pause"); } } }; /** * Listen some events. */ function bind() { var options = Splide.options; var sibling = Splide.sibling; var elms = [Splide.root, sibling ? sibling.root : null]; if (options.pauseOnHover) { switchOn(elms, 'mouseleave', PAUSE_FLAGS.HOVER, true); switchOn(elms, 'mouseenter', PAUSE_FLAGS.HOVER, false); } if (options.pauseOnFocus) { switchOn(elms, 'focusout', PAUSE_FLAGS.FOCUS, true); switchOn(elms, 'focusin', PAUSE_FLAGS.FOCUS, false); } if (Elements.play) { Splide.on('click', function () { // Need to be removed a focus flag at first. Autoplay.play(PAUSE_FLAGS.FOCUS); Autoplay.play(PAUSE_FLAGS.MANUAL); }, Elements.play); } if (Elements.pause) { switchOn([Elements.pause], 'click', PAUSE_FLAGS.MANUAL, false); } Splide.on('move refresh', function () { Autoplay.play(); }) // Rewind the timer. .on('destroy', function () { Autoplay.pause(); }); } /** * Play or pause on the given event. * * @param {Element[]} elms - Elements. * @param {string} event - An event name or names. * @param {number} flag - A pause flag defined on the top. * @param {boolean} play - Determine whether to play or pause. */ function switchOn(elms, event, flag, play) { elms.forEach(function (elm) { Splide.on(event, function () { Autoplay[play ? 'play' : 'pause'](flag); }, elm); }); } return Autoplay; }; ; // CONCATENATED MODULE: ./src/js/components/cover/index.js /** * The component for change an img element to background image of its wrapper. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for change an img element to background image of its wrapper. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * * @return {Object} - The component object. */ /* harmony default export */var cover = function cover(Splide, Components) { /** * Hold options. * * @type {Object} */ var options = Splide.options; /** * Cover component object. * * @type {Object} */ var Cover = { /** * Required only when "cover" option is true. * * @type {boolean} */ required: options.cover, /** * Called when the component is mounted. */ mount: function mount() { Splide.on('lazyload:loaded', function (img) { cover(img, false); }); Splide.on('mounted updated refresh', function () { return apply(false); }); }, /** * Destroy. */ destroy: function destroy() { apply(true); } }; /** * Apply "cover" to all slides. * * @param {boolean} uncover - If true, "cover" will be clear. */ function apply(uncover) { Components.Elements.each(function (Slide) { var img = child(Slide.slide, 'IMG') || child(Slide.container, 'IMG'); if (img && img.src) { cover(img, uncover); } }); } /** * Set background image of the parent element, using source of the given image element. * * @param {Element} img - An image element. * @param {boolean} uncover - Reset "cover". */ function cover(img, uncover) { applyStyle(img.parentElement, { background: uncover ? '' : "center/cover no-repeat url(\"" + img.src + "\")" }); applyStyle(img, { display: uncover ? '' : 'none' }); } return Cover; }; ; // CONCATENATED MODULE: ./src/js/components/arrows/path.js /** * Export vector path for an arrow. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * Namespace definition for SVG element. * * @type {string} */ var XML_NAME_SPACE = 'http://www.w3.org/2000/svg'; /** * The arrow vector path. * * @type {number} */ var PATH = 'm15.5 0.932-4.3 4.38 14.5 14.6-14.5 14.5 4.3 4.4 14.6-14.6 4.4-4.3-4.4-4.4-14.6-14.6z'; /** * SVG width and height. * * @type {number} */ var SIZE = 40; ; // CONCATENATED MODULE: ./src/js/components/arrows/index.js /** * The component for appending prev/next arrows. * * @author Naotoshi Fujita * @copyright Naotoshi Fujita. All rights reserved. */ /** * The component for appending prev/next arrows. * * @param {Splide} Splide - A Splide instance. * @param {Object} Components - An object containing components. * @param {string} name - A component name as a lowercase string. * * @return {Object} - The component object. */ /* harmony default export */var arrows = function arrows(Splide, Components, name) { /** * Previous arrow element. * * @type {Element|undefined} */ var prev; /** * Next arrow element. * * @type {Element|undefined} */ var next; /** * Store the class list. * * @type {Object} */ var classes = Splide.classes; /** * Hold the root element. * * @type {Element} */ var root = Splide.root; /** * Whether arrows are created programmatically or not. * * @type {boolean} */ var created; /** * Hold the Elements component. * * @type {Object} */ var Elements = Components.Elements; /** * Arrows component object. * * @type {Object} */ var Arrows = { /** * Required when the arrows option is true. * * @type {boolean} */ required: Splide.options.arrows, /** * Called when the component is mounted. */ mount: function mount() { // Attempt to get arrows from HTML source. prev = Elements.arrows.prev; next = Elements.arrows.next; // If arrows were not found in HTML, let's generate them. if ((!prev || !next) && Splide.options.arrows) { prev = createArrow(true); next = createArrow(false); created = true; appendArrows(); } if (prev && next) { bind(); } this.arrows = { prev: prev, next: next }; }, /** * Called after all components are mounted. */ mounted: function mounted() { Splide.emit(name + ":mounted", prev, next); }, /** * Destroy. */ destroy: function destroy() { removeAttribute([prev, next], 'disabled'); if (created) { dom_remove(prev.parentElement); } } }; /** * Listen to native and custom events. */ function bind() { Splide.on('click', function () { Splide.go('<'); }, prev).on('click', function () { Splide.go('>'); }, next).on('mounted move updated refresh', updateDisabled); } /** * Update a disabled attribute. */ function updateDisabled() { var _Components$Controlle = Components.Controller, prevIndex = _Components$Controlle.prevIndex, nextIndex = _Components$Controlle.nextIndex; var isEnough = Splide.length > Splide.options.perPage || Splide.is(LOOP); prev.disabled = prevIndex < 0 || !isEnough; next.disabled = nextIndex < 0 || !isEnough; Splide.emit(name + ":updated", prev, next, prevIndex, nextIndex); } /** * Create a wrapper element and append arrows. */ function appendArrows() { var wrapper = create('div', { "class": classes.arrows }); append(wrapper, prev); append(wrapper, next); var slider = Elements.slider; var parent = Splide.options.arrows === 'slider' && slider ? slider : root; before(wrapper, parent.firstElementChild); } /** * Create an arrow element. * * @param {boolean} prev - Determine to create a prev arrow or next arrow. * * @return {Element} - A created arrow element. */ function createArrow(prev) { var arrow = "