Matheus Garcia
3 years ago
123 changed files with 28135 additions and 1 deletions
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/aria",["exports","jquery","core/pending"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=d(b);c=d(c);function d(a){return a&&a.__esModule?a:{default:a}}var e=function(){var a=!1,d=function(){a=!0},e=function(){var b=a;a=!1;return b};document.addEventListener("keydown",function(a){if(a.target.matches("[data-toggle=\"dropdown\"]")){var b=a.key;if("ArrowUp"==b){d()}if(" "==b||"Enter"==b){a.preventDefault();a.target.click()}}});var f=function(a){setTimeout(function delayedFocus(b){a.focus();b.resolve()},50,new c.default("core/aria:delayed-focus"))};(0,b.default)(".dropdown").on("shown.bs.dropdown",function(a){var b=a.target.querySelector("[role=\"menu\"]"),c=!1,d=!1;if(b){c=b.querySelectorAll("[role=\"menuitem\"]")}if(c&&0<c.length){if(e()){d=c[c.length-1]}else{d=c[0]}}if(d){f(d)}});document.addEventListener("keypress",function(a){if(a.target.matches(".dropdown [role=\"menu\"] [role=\"menuitem\"]")){var g=a.target.closest("[role=\"menu\"]");if(!g){return}var h=g.querySelectorAll("[role=\"menuitem\"]");if(!h){return}for(var b=a.key.toLowerCase(),c=0;c<h.length;c++){var d=h[c],e=d.text.trim().toLowerCase();if(0==e.indexOf(b)){f(d);break}}}});document.addEventListener("keydown",function(a){if(a.target.matches(".dropdown [role=\"menu\"] [role=\"menuitem\"]")){var b=a.key,c=!1,d=a.target.closest("[role=\"menu\"]");if(!d){return}var e=d.querySelectorAll("[role=\"menuitem\"]");if(!e){return}if("ArrowDown"==b){for(var g=0;g<e.length-1;g++){if(e[g]==a.target){c=e[g+1];break}}if(!c){c=e[0]}}else if("ArrowUp"==b){for(var h=1;h<e.length;h++){if(e[h]==a.target){c=e[h-1];break}}if(!c){c=e[e.length-1]}}else if("Home"==b){c=e[0]}else if("End"==b){c=e[e.length-1]}if(c){a.preventDefault();f(c)}}});(0,b.default)(".dropdown").on("hidden.bs.dropdown",function(a){var b=a.target.querySelector("[data-toggle=\"dropdown\"]");if(b){f(b)}})},f=function(){window.addEventListener("load",function(){var a=document.querySelectorAll("[data-aria-autofocus=\"true\"][role=\"alert\"]");Array.prototype.forEach.call(a,function(a){a.innerHTML+=" ";a.removeAttribute("data-aria-autofocus")})})},g=function(a){for(var c=a.target.closest("[role=\"tablist\"]"),d="vertical"==c.getAttribute("aria-orientation"),e=window.right_to_left(),f=d?"ArrowDown":e?"ArrowLeft":"ArrowRight",g=d?"ArrowUp":e?"ArrowRight":"ArrowLeft",h=Array.prototype.filter.call(c.querySelectorAll("[role=\"tab\"]"),function(a){return"none"!==getComputedStyle(a).display}),j=0;j<h.length;j++){h[j].index=j}switch(a.key){case f:a.preventDefault();if(a.target.index!==void 0&&h[a.target.index+1]){h[a.target.index+1].focus()}else{h[0].focus()}break;case g:a.preventDefault();if(a.target.index!==void 0&&h[a.target.index-1]){h[a.target.index-1].focus()}else{h[h.length-1].focus()}break;case"Home":a.preventDefault();h[0].focus();break;case"End":a.preventDefault();h[h.length-1].focus();break;case"Enter":case" ":a.preventDefault();(0,b.default)(a.target).tab("show");h.forEach(function(a){a.tabIndex=-1});a.target.tabIndex=0;}},h=function(){document.addEventListener("keydown",function(a){if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight","Home","End","Enter"," "].includes(a.key)){if(a.target.matches("[role=\"tablist\"] [role=\"tab\"]")){g(a)}}});document.addEventListener("click",function(a){if(a.target.matches("[role=\"tablist\"] [role=\"tab\"]")){var c=a.target.closest("[role=\"tablist\"]").querySelectorAll("[role=\"tab\"]");a.preventDefault();(0,b.default)(a.target).tab("show");c.forEach(function(a){a.tabIndex=-1});a.target.tabIndex=0}})};a.init=function init(){e();f();h()}}); |
|||
//# sourceMappingURL=aria.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/bootstrap/alert",["exports","jquery","./util"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=d(b);c=d(c);function d(a){return a&&a.__esModule?a:{default:a}}function e(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function f(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function g(a,b,c){if(b)f(a.prototype,b);if(c)f(a,c);return a}var h="bs.alert",i=".".concat(h),j=b.default.fn.alert,k="close".concat(i),l="closed".concat(i),m="click".concat(i).concat(".data-api"),n=function(){function a(b){e(this,a);this._element=b}g(a,[{key:"close",value:function close(a){var b=this._element;if(a){b=this._getRootElement(a)}var c=this._triggerCloseEvent(b);if(c.isDefaultPrevented()){return}this._removeElement(b)}},{key:"dispose",value:function dispose(){b.default.removeData(this._element,h);this._element=null}},{key:"_getRootElement",value:function _getRootElement(a){var d=c.default.getSelectorFromElement(a),e=!1;if(d){e=document.querySelector(d)}if(!e){e=(0,b.default)(a).closest(".".concat("alert"))[0]}return e}},{key:"_triggerCloseEvent",value:function _triggerCloseEvent(a){var c=b.default.Event(k);(0,b.default)(a).trigger(c);return c}},{key:"_removeElement",value:function _removeElement(a){var d=this;(0,b.default)(a).removeClass("show");if(!(0,b.default)(a).hasClass("fade")){this._destroyElement(a);return}var e=c.default.getTransitionDurationFromElement(a);(0,b.default)(a).one(c.default.TRANSITION_END,function(b){return d._destroyElement(a,b)}).emulateTransitionEnd(e)}},{key:"_destroyElement",value:function _destroyElement(a){(0,b.default)(a).detach().trigger(l).remove()}}],[{key:"_jQueryInterface",value:function _jQueryInterface(c){return this.each(function(){var d=(0,b.default)(this),e=d.data(h);if(!e){e=new a(this);d.data(h,e)}if("close"===c){e[c](this)}})}},{key:"_handleDismiss",value:function _handleDismiss(a){return function(b){if(b){b.preventDefault()}a.close(this)}}},{key:"VERSION",get:function get(){return"4.6.0"}}]);return a}();(0,b.default)(document).on(m,"[data-dismiss=\"alert\"]",n._handleDismiss(new n));b.default.fn.alert=n._jQueryInterface;b.default.fn.alert.Constructor=n;b.default.fn.alert.noConflict=function(){b.default.fn.alert=j;return n._jQueryInterface};a.default=n;return a.default}); |
|||
//# sourceMappingURL=alert.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/bootstrap/button",["exports","jquery"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function d(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function e(a,b,c){if(b)d(a.prototype,b);if(c)d(a,c);return a}var f="bs.button",g=".".concat(f),h=".data-api",i=b.default.fn.button,j="active",k="[data-toggle^=\"button\"]",l="input:not([type=\"hidden\"])",m=".btn",n="click".concat(g).concat(h),o="focus".concat(g).concat(h," ")+"blur".concat(g).concat(h),p="load".concat(g).concat(h),q=function(){function a(b){c(this,a);this._element=b;this.shouldAvoidTriggerChange=!1}e(a,[{key:"toggle",value:function toggle(){var a=!0,c=!0,d=(0,b.default)(this._element).closest("[data-toggle=\"buttons\"]")[0];if(d){var e=this._element.querySelector(l);if(e){if("radio"===e.type){if(e.checked&&this._element.classList.contains(j)){a=!1}else{var f=d.querySelector(".active");if(f){(0,b.default)(f).removeClass(j)}}}if(a){if("checkbox"===e.type||"radio"===e.type){e.checked=!this._element.classList.contains(j)}if(!this.shouldAvoidTriggerChange){(0,b.default)(e).trigger("change")}}e.focus();c=!1}}if(!(this._element.hasAttribute("disabled")||this._element.classList.contains("disabled"))){if(c){this._element.setAttribute("aria-pressed",!this._element.classList.contains(j))}if(a){(0,b.default)(this._element).toggleClass(j)}}}},{key:"dispose",value:function dispose(){b.default.removeData(this._element,f);this._element=null}}],[{key:"_jQueryInterface",value:function _jQueryInterface(c,d){return this.each(function(){var e=(0,b.default)(this),g=e.data(f);if(!g){g=new a(this);e.data(f,g)}g.shouldAvoidTriggerChange=d;if("toggle"===c){g[c]()}})}},{key:"VERSION",get:function get(){return"4.6.0"}}]);return a}();(0,b.default)(document).on(n,k,function(a){var c=a.target,d=c;if(!(0,b.default)(c).hasClass("btn")){c=(0,b.default)(c).closest(m)[0]}if(!c||c.hasAttribute("disabled")||c.classList.contains("disabled")){a.preventDefault()}else{var e=c.querySelector(l);if(e&&(e.hasAttribute("disabled")||e.classList.contains("disabled"))){a.preventDefault();return}if("INPUT"===d.tagName||"LABEL"!==c.tagName){q._jQueryInterface.call((0,b.default)(c),"toggle","INPUT"===d.tagName)}}}).on(o,k,function(a){var c=(0,b.default)(a.target).closest(m)[0];(0,b.default)(c).toggleClass("focus",/^focus(in)?$/.test(a.type))});(0,b.default)(window).on(p,function(){for(var a=[].slice.call(document.querySelectorAll("[data-toggle=\"buttons\"] .btn")),b=0,c=a.length;b<c;b++){var d=a[b],e=d.querySelector(l);if(e.checked||e.hasAttribute("checked")){d.classList.add(j)}else{d.classList.remove(j)}}a=[].slice.call(document.querySelectorAll("[data-toggle=\"button\"]"));for(var f=0,g=a.length,h;f<g;f++){h=a[f];if("true"===h.getAttribute("aria-pressed")){h.classList.add(j)}else{h.classList.remove(j)}}});b.default.fn.button=q._jQueryInterface;b.default.fn.button.Constructor=q;b.default.fn.button.noConflict=function(){b.default.fn.button=i;return q._jQueryInterface};a.default=q;return a.default}); |
|||
//# sourceMappingURL=button.min.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/bootstrap/tab",["exports","jquery","./util"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=d(b);c=d(c);function d(a){return a&&a.__esModule?a:{default:a}}function e(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function f(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function g(a,b,c){if(b)f(a.prototype,b);if(c)f(a,c);return a}var h="bs.tab",i=".".concat(h),j=b.default.fn.tab,k="hide".concat(i),l="hidden".concat(i),m="show".concat(i),n="shown".concat(i),o="click".concat(i).concat(".data-api"),p="active",q="fade",r="show",s=".active",t="> li > .active",u=function(){function a(b){e(this,a);this._element=b}g(a,[{key:"show",value:function show(){var a=this;if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&(0,b.default)(this._element).hasClass(p)||(0,b.default)(this._element).hasClass("disabled")){return}var d,e,f=(0,b.default)(this._element).closest(".nav, .list-group")[0],g=c.default.getSelectorFromElement(this._element);if(f){var o="UL"===f.nodeName||"OL"===f.nodeName?t:s;e=b.default.makeArray((0,b.default)(f).find(o));e=e[e.length-1]}var h=b.default.Event(k,{relatedTarget:this._element}),i=b.default.Event(m,{relatedTarget:e});if(e){(0,b.default)(e).trigger(h)}(0,b.default)(this._element).trigger(i);if(i.isDefaultPrevented()||h.isDefaultPrevented()){return}if(g){d=document.querySelector(g)}this._activate(this._element,f);var j=function(){var c=b.default.Event(l,{relatedTarget:a._element}),d=b.default.Event(n,{relatedTarget:e});(0,b.default)(e).trigger(c);(0,b.default)(a._element).trigger(d)};if(d){this._activate(d,d.parentNode,j)}else{j()}}},{key:"dispose",value:function dispose(){b.default.removeData(this._element,h);this._element=null}},{key:"_activate",value:function _activate(a,d,e){var f=this,g=d&&("UL"===d.nodeName||"OL"===d.nodeName)?(0,b.default)(d).find(t):(0,b.default)(d).children(s),h=g[0],i=e&&h&&(0,b.default)(h).hasClass(q),j=function(){return f._transitionComplete(a,h,e)};if(h&&i){var k=c.default.getTransitionDurationFromElement(h);(0,b.default)(h).removeClass(r).one(c.default.TRANSITION_END,j).emulateTransitionEnd(k)}else{j()}}},{key:"_transitionComplete",value:function _transitionComplete(a,d,e){if(d){(0,b.default)(d).removeClass(p);var f=(0,b.default)(d.parentNode).find("> .dropdown-menu .active")[0];if(f){(0,b.default)(f).removeClass(p)}if("tab"===d.getAttribute("role")){d.setAttribute("aria-selected",!1)}}(0,b.default)(a).addClass(p);if("tab"===a.getAttribute("role")){a.setAttribute("aria-selected",!0)}c.default.reflow(a);if(a.classList.contains(q)){a.classList.add(r)}if(a.parentNode&&(0,b.default)(a.parentNode).hasClass("dropdown-menu")){var g=(0,b.default)(a).closest(".dropdown")[0];if(g){var h=[].slice.call(g.querySelectorAll(".dropdown-toggle"));(0,b.default)(h).addClass(p)}a.setAttribute("aria-expanded",!0)}if(e){e()}}}],[{key:"_jQueryInterface",value:function _jQueryInterface(c){return this.each(function(){var d=(0,b.default)(this),e=d.data(h);if(!e){e=new a(this);d.data(h,e)}if("string"==typeof c){if("undefined"==typeof e[c]){throw new TypeError("No method named \"".concat(c,"\""))}e[c]()}})}},{key:"VERSION",get:function get(){return"4.6.0"}}]);return a}();(0,b.default)(document).on(o,"[data-toggle=\"tab\"], [data-toggle=\"pill\"], [data-toggle=\"list\"]",function(a){a.preventDefault();u._jQueryInterface.call((0,b.default)(this),"show")});b.default.fn.tab=u._jQueryInterface;b.default.fn.tab.Constructor=u;b.default.fn.tab.noConflict=function(){b.default.fn.tab=j;return u._jQueryInterface};a.default=u;return a.default}); |
|||
//# sourceMappingURL=tab.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/bootstrap/toast",["exports","jquery","./util"],function(a,b,c){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=d(b);c=d(c);function d(a){return a&&a.__esModule?a:{default:a}}function e(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){e=function(a){return typeof a}}else{e=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return e(a)}function f(a,b){var c=Object.keys(a);if(Object.getOwnPropertySymbols){var d=Object.getOwnPropertySymbols(a);if(b)d=d.filter(function(b){return Object.getOwnPropertyDescriptor(a,b).enumerable});c.push.apply(c,d)}return c}function g(a){for(var b=1,c;b<arguments.length;b++){c=null!=arguments[b]?arguments[b]:{};if(b%2){f(Object(c),!0).forEach(function(b){h(a,b,c[b])})}else if(Object.getOwnPropertyDescriptors){Object.defineProperties(a,Object.getOwnPropertyDescriptors(c))}else{f(Object(c)).forEach(function(b){Object.defineProperty(a,b,Object.getOwnPropertyDescriptor(c,b))})}}return a}function h(a,b,c){if(b in a){Object.defineProperty(a,b,{value:c,enumerable:!0,configurable:!0,writable:!0})}else{a[b]=c}return a}function i(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function j(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function k(a,b,c){if(b)j(a.prototype,b);if(c)j(a,c);return a}var l="bs.toast",m=".".concat(l),n=b.default.fn.toast,o="click.dismiss".concat(m),p="hide".concat(m),q="hidden".concat(m),r="show".concat(m),s="shown".concat(m),t="hide",u="show",v="showing",w={animation:"boolean",autohide:"boolean",delay:"number"},x={animation:!0,autohide:!0,delay:500},y=function(){function a(b,c){i(this,a);this._element=b;this._config=this._getConfig(c);this._timeout=null;this._setListeners()}k(a,[{key:"show",value:function show(){var a=this,d=b.default.Event(r);(0,b.default)(this._element).trigger(d);if(d.isDefaultPrevented()){return}this._clearTimeout();if(this._config.animation){this._element.classList.add("fade")}var e=function(){a._element.classList.remove(v);a._element.classList.add(u);(0,b.default)(a._element).trigger(s);if(a._config.autohide){a._timeout=setTimeout(function(){a.hide()},a._config.delay)}};this._element.classList.remove(t);c.default.reflow(this._element);this._element.classList.add(v);if(this._config.animation){var f=c.default.getTransitionDurationFromElement(this._element);(0,b.default)(this._element).one(c.default.TRANSITION_END,e).emulateTransitionEnd(f)}else{e()}}},{key:"hide",value:function hide(){if(!this._element.classList.contains(u)){return}var a=b.default.Event(p);(0,b.default)(this._element).trigger(a);if(a.isDefaultPrevented()){return}this._close()}},{key:"dispose",value:function dispose(){this._clearTimeout();if(this._element.classList.contains(u)){this._element.classList.remove(u)}(0,b.default)(this._element).off(o);b.default.removeData(this._element,l);this._element=null;this._config=null}},{key:"_getConfig",value:function _getConfig(a){a=g({},x,{},(0,b.default)(this._element).data(),{},"object"===e(a)&&a?a:{});c.default.typeCheckConfig("toast",a,this.constructor.DefaultType);return a}},{key:"_setListeners",value:function _setListeners(){var a=this;(0,b.default)(this._element).on(o,"[data-dismiss=\"toast\"]",function(){return a.hide()})}},{key:"_close",value:function _close(){var a=this,d=function(){a._element.classList.add(t);(0,b.default)(a._element).trigger(q)};this._element.classList.remove(u);if(this._config.animation){var e=c.default.getTransitionDurationFromElement(this._element);(0,b.default)(this._element).one(c.default.TRANSITION_END,d).emulateTransitionEnd(e)}else{d()}}},{key:"_clearTimeout",value:function _clearTimeout(){clearTimeout(this._timeout);this._timeout=null}}],[{key:"_jQueryInterface",value:function _jQueryInterface(c){return this.each(function(){var d=(0,b.default)(this),f=d.data(l),g="object"===e(c)&&c;if(!f){f=new a(this,g);d.data(l,f)}if("string"==typeof c){if("undefined"==typeof f[c]){throw new TypeError("No method named \"".concat(c,"\""))}f[c](this)}})}},{key:"VERSION",get:function get(){return"4.6.0"}},{key:"DefaultType",get:function get(){return w}},{key:"Default",get:function get(){return x}}]);return a}();b.default.fn.toast=y._jQueryInterface;b.default.fn.toast.Constructor=y;b.default.fn.toast.noConflict=function(){b.default.fn.toast=n;return y._jQueryInterface};a.default=y;return a.default}); |
|||
//# sourceMappingURL=toast.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/bootstrap/tools/sanitizer",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.sanitizeHtml=function(a,c,d){if(0===a.length){return a}if(d&&"function"==typeof d){return d(a)}for(var e=new window.DOMParser,f=e.parseFromString(a,"text/html"),g=Object.keys(c),h=[].slice.call(f.body.querySelectorAll("*")),j=function(a){var d=h[a],e=d.nodeName.toLowerCase();if(-1===g.indexOf(d.nodeName.toLowerCase())){d.parentNode.removeChild(d);return"continue"}var f=[].slice.call(d.attributes),i=[].concat(c["*"]||[],c[e]||[]);f.forEach(function(a){if(!b(a,i)){d.removeAttribute(a.nodeName)}})},k=0,l=h.length,m;k<l;k++){m=j(k,l);if("continue"===m)continue}return f.body.innerHTML};a.DefaultWhitelist=void 0;var c=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"];a.DefaultWhitelist={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]};function b(a,b){var d=a.nodeName.toLowerCase();if(-1!==b.indexOf(d)){if(-1!==c.indexOf(d)){return!!(a.nodeValue.match(/^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/gi)||a.nodeValue.match(/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i))}return!0}for(var e=b.filter(function(a){return a instanceof RegExp}),f=0,g=e.length;f<g;f++){if(d.match(e[f])){return!0}}return!1}}); |
|||
//# sourceMappingURL=sanitizer.min.js.map
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/bootstrap/util",["exports","jquery"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a){if(null===a||"undefined"==typeof a){return"".concat(a)}return{}.toString.call(a).match(/\s([a-z]+)/i)[1].toLowerCase()}function d(){return{bindType:"transitionend",delegateType:"transitionend",handle:function handle(a){if((0,b.default)(a.target).is(this)){return a.handleObj.handler.apply(this,arguments)}}}}function e(a){var c=this,d=!1;(0,b.default)(this).one(g.TRANSITION_END,function(){d=!0});setTimeout(function(){if(!d){g.triggerTransitionEnd(c)}},a);return this}function f(){b.default.fn.emulateTransitionEnd=e;b.default.event.special[g.TRANSITION_END]=d()}var g={TRANSITION_END:"bsTransitionEnd",getUID:function getUID(a){do{a+=~~(Math.random()*1e6)}while(document.getElementById(a));return a},getSelectorFromElement:function getSelectorFromElement(a){var b=a.getAttribute("data-target");if(!b||"#"===b){var c=a.getAttribute("href");b=c&&"#"!==c?c.trim():""}try{return document.querySelector(b)?b:null}catch(a){return null}},getTransitionDurationFromElement:function getTransitionDurationFromElement(a){if(!a){return 0}var c=(0,b.default)(a).css("transition-duration"),d=(0,b.default)(a).css("transition-delay"),e=parseFloat(c),f=parseFloat(d);if(!e&&!f){return 0}c=c.split(",")[0];d=d.split(",")[0];return(parseFloat(c)+parseFloat(d))*1e3},reflow:function reflow(a){return a.offsetHeight},triggerTransitionEnd:function triggerTransitionEnd(a){(0,b.default)(a).trigger("transitionend")},supportsTransitionEnd:function supportsTransitionEnd(){return!0},isElement:function isElement(a){return(a[0]||a).nodeType},typeCheckConfig:function typeCheckConfig(a,b,d){for(var i in d){if(Object.prototype.hasOwnProperty.call(d,i)){var e=d[i],f=b[i],h=f&&g.isElement(f)?"element":c(f);if(!new RegExp(e).test(h)){throw new Error("".concat(a.toUpperCase(),": ")+"Option \"".concat(i,"\" provided type \"").concat(h,"\" ")+"but expected type \"".concat(e,"\"."))}}}},findShadowRoot:function findShadowRoot(a){if(!document.documentElement.attachShadow){return null}if("function"==typeof a.getRootNode){var b=a.getRootNode();return b instanceof ShadowRoot?b:null}if(a instanceof ShadowRoot){return a}if(!a.parentNode){return null}return g.findShadowRoot(a.parentNode)},jQueryDetection:function jQueryDetection(){if("undefined"==typeof b.default){throw new TypeError("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.")}var a=b.default.fn.jquery.split(" ")[0].split("."),c=9;if(a[0]<2&&a[1]<c||a[0]===1&&a[1]===c&&a[2]<1||a[0]>=4){throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}}};g.jQueryDetection();f();a.default=g;return a.default}); |
|||
//# sourceMappingURL=util.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/drawer",["jquery","core/custom_interaction_events","core/log","core/pubsub","core/aria"],function(a,b,c,d,e){var f={TOGGLE_REGION:"[data-region=\"drawer-toggle\"]",TOGGLE_ACTION:"[data-action=\"toggle-drawer\"]",TOGGLE_TARGET:"aria-controls",TOGGLE_SIDE:"left",BODY:"body",SECTION:".list-group-item[href*=\"#section-\"]",DRAWER:"#nav-drawer"},g=768>a(document).width(),h=function(){if(!a(f.TOGGLE_REGION).length){c.debug("Page is missing a drawer region")}if(!a(f.TOGGLE_ACTION).length){c.debug("Page is missing a drawer toggle link")}a(f.TOGGLE_REGION).each(function(b,c){var d=a(c).find(f.TOGGLE_ACTION),e=d.attr("aria-controls"),h=a(document.getElementById(e)),i="false"==d.attr("aria-expanded"),j=d.attr("data-side"),k=a(f.BODY),l=d.attr("data-preference");if(g){M.util.set_user_preference(l,"false")}h.on("mousewheel DOMMouseScroll",this.preventPageScroll);if(!i){k.addClass("drawer-open-"+j);d.attr("aria-expanded","true")}else{d.attr("aria-expanded","false")}}.bind(this));this.registerEventListeners();if(g){this.closeAll()}};h.prototype.closeAll=function(){a(f.TOGGLE_REGION).each(function(b,c){var d=a(c).find(f.TOGGLE_ACTION),h=d.attr("data-side"),i=a(f.BODY),j=d.attr("aria-controls"),k=a(document.getElementById(j)),l=d.attr("data-preference");d.attr("aria-expanded","false");i.removeClass("drawer-open-"+h);e.hide(k.get());k.addClass("closed");if(!g){M.util.set_user_preference(l,"false")}})};h.prototype.toggleDrawer=function(b){var c=a(b.target).closest("[data-action=toggle-drawer]"),h=c.attr("aria-controls"),i=a(document.getElementById(h)),j=a(f.BODY),k=c.attr("data-side"),l=c.attr("data-preference");if(g){M.util.set_user_preference(l,"false")}j.addClass("drawer-ease");var m="true"==c.attr("aria-expanded");if(!m){c.attr("aria-expanded","true");e.unhide(i.get());i.focus();j.addClass("drawer-open-"+k);i.removeClass("closed");if(!g){M.util.set_user_preference(l,"true")}}else{j.removeClass("drawer-open-"+k);c.attr("aria-expanded","false");i.addClass("closed").delay(500).queue(function(){if(a(this).hasClass("closed")){e.hide(this)}a(this).dequeue()});if(!g){M.util.set_user_preference(l,"false")}}d.publish("nav-drawer-toggle-start",m)};h.prototype.preventPageScroll=function(b){var c=b.wheelDelta||b.originalEvent&&b.originalEvent.wheelDelta||-b.originalEvent.detail,d=0<=this.scrollTop+a(this).outerHeight()-this.scrollHeight,e=0>=this.scrollTop;if(0>c&&d||0<c&&e){b.preventDefault()}};h.prototype.registerEventListeners=function(){a(f.TOGGLE_ACTION).each(function(c,d){b.define(a(d),[b.events.activate]);a(d).on(b.events.activate,function(a,b){this.toggleDrawer(b.originalEvent);b.originalEvent.preventDefault()}.bind(this))}.bind(this));a(f.SECTION).click(function(){if(g){this.closeAll()}}.bind(this));a(f.DRAWER).on("webkitTransitionEnd msTransitionEnd transitionend",function(b){var c=a(b.target).closest(f.DRAWER),e=!!c.attr("aria-hidden");d.publish("nav-drawer-toggle-end",e)})};return{init:function init(){return new h}}}); |
|||
//# sourceMappingURL=drawer.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/form-display-errors",["jquery","core/event"],function(a,b){return{enhance:function enhance(c){var d=document.getElementById(c);if(!d){return}a(d).on(b.Events.FORM_FIELD_VALIDATION,function(b,c){b.preventDefault();var e=a(d).closest(".form-group"),f=e.find(".form-control-feedback"),g=f.attr("id"),h=a(d).attr("aria-describedby");if("undefined"==typeof h){h=""}var i=[];if(h.length){i=h.split(" ")}var j=i.indexOf(g);if("TEXTAREA"==a(d).prop("tagName")&&e.find("[contenteditable]")){d=e.find("[contenteditable]")}if(""!==c){e.addClass("has-danger");e.data("client-validation-error",!0);a(d).addClass("is-invalid");if(-1===j){i.push(g);a(d).attr("aria-describedby",i.join(" "))}a(d).attr("aria-invalid",!0);f.attr("tabindex",0);f.html(c);if(!f.is(":visible")){f.show();f.focus()}}else{if(!0===e.data("client-validation-error")){e.removeClass("has-danger");e.data("client-validation-error",!1);a(d).removeClass("is-invalid");if(-1<j){i.splice(j,1)}if(i.length){h=i.join(" ");a(d).attr("aria-describedby",h)}else{a(d).removeAttr("aria-describedby")}a(d).attr("aria-invalid",!1);f.hide()}}});var e=d.closest("form");if(e&&!("ilbFormErrorsEnhanced"in e.dataset)){e.addEventListener("submit",function(){var b=a(".form-control-feedback:visible");if(b.length){b[0].focus()}});e.dataset.ilbFormErrorsEnhanced=1}}}}); |
|||
//# sourceMappingURL=form-display-errors.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/index",["exports","./bootstrap/alert","./bootstrap/button","./bootstrap/carousel","./bootstrap/collapse","./bootstrap/dropdown","./bootstrap/modal","./bootstrap/popover","./bootstrap/scrollspy","./bootstrap/tab","./bootstrap/toast","./bootstrap/tooltip","./bootstrap/util"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"Alert",{enumerable:!0,get:function get(){return b.default}});Object.defineProperty(a,"Button",{enumerable:!0,get:function get(){return c.default}});Object.defineProperty(a,"Carousel",{enumerable:!0,get:function get(){return d.default}});Object.defineProperty(a,"Collapse",{enumerable:!0,get:function get(){return e.default}});Object.defineProperty(a,"Dropdown",{enumerable:!0,get:function get(){return f.default}});Object.defineProperty(a,"Modal",{enumerable:!0,get:function get(){return g.default}});Object.defineProperty(a,"Popover",{enumerable:!0,get:function get(){return h.default}});Object.defineProperty(a,"Scrollspy",{enumerable:!0,get:function get(){return i.default}});Object.defineProperty(a,"Tab",{enumerable:!0,get:function get(){return j.default}});Object.defineProperty(a,"Toast",{enumerable:!0,get:function get(){return k.default}});Object.defineProperty(a,"Tooltip",{enumerable:!0,get:function get(){return l.default}});Object.defineProperty(a,"Util",{enumerable:!0,get:function get(){return m.default}});b=n(b);c=n(c);d=n(d);e=n(e);f=n(f);g=n(g);h=n(h);i=n(i);j=n(j);k=n(k);l=n(l);m=n(m);function n(a){return a&&a.__esModule?a:{default:a}}}); |
|||
//# sourceMappingURL=index.min.js.map
|
@ -0,0 +1 @@ |
|||
{"version":3,"sources":["../src/index.js"],"names":[],"mappings":"g6CAOA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,O","sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.6.0): index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './bootstrap/alert';\nimport Button from './bootstrap/button';\nimport Carousel from './bootstrap/carousel';\nimport Collapse from './bootstrap/collapse';\nimport Dropdown from './bootstrap/dropdown';\nimport Modal from './bootstrap/modal';\nimport Popover from './bootstrap/popover';\nimport Scrollspy from './bootstrap/scrollspy';\nimport Tab from './bootstrap/tab';\nimport Toast from './bootstrap/toast';\nimport Tooltip from './bootstrap/tooltip';\nimport Util from './bootstrap/util';\n\nexport {\n Util,\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Popover,\n Scrollspy,\n Tab,\n Toast,\n Tooltip\n};\n"],"file":"index.min.js"} |
@ -0,0 +1,2 @@ |
|||
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("theme_ilb/loader",["exports","jquery","./aria","./index","core/pending","./scroll","./pending"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"Bootstrap",{enumerable:!0,get:function get(){return d.default}});b=j(b);c=i(c);d=j(d);e=j(e);f=j(f);g=j(g);function h(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;h=function(){return a};return a}function i(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=h();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function j(a){return a&&a.__esModule?a:{default:a}}var k=function(){(0,b.default)("a[data-toggle=\"tab\"]").on("shown.bs.tab",function(a){var c=(0,b.default)(a.target).attr("href");if(history.replaceState){history.replaceState(null,null,c)}else{location.hash=c}});var a=window.location.hash;if(a){var c=document.querySelector(".nav-link[href=\""+a+"\"]");if(c){c.click()}}},l=function(){(0,b.default)("body").popover({container:"body",selector:"[data-toggle=\"popover\"]",trigger:"focus"});document.addEventListener("keydown",function(a){if("Escape"===a.key&&a.target.closest("[data-toggle=\"popover\"]")){(0,b.default)(a.target).popover("hide")}})},m=function(){(0,b.default)("body").tooltip({container:"body",selector:"[data-toggle=\"tooltip\"]"})},n=new e.default("theme_ilb/loader:init");(0,g.default)();c.init();k();l();m();new f.default().init();b.default.fn.dropdown.Constructor.Default.flip=!1;n.resolve()}); |
|||
//# sourceMappingURL=loader.min.js.map
|
@ -0,0 +1 @@ |
|||
{"version":3,"sources":["../src/loader.js"],"names":["rememberTabs","on","e","hash","target","attr","history","replaceState","location","window","tab","document","querySelector","click","enablePopovers","popover","container","selector","trigger","addEventListener","key","closest","enableTooltips","tooltip","pendingPromise","Pending","Aria","init","Scroll","$","fn","dropdown","Constructor","Default","flip","resolve"],"mappings":"8jBAwBA,OACA,OACA,OACA,OACA,OACA,O,4lBAKMA,CAAAA,CAAY,CAAG,UAAM,CACvB,cAAE,wBAAF,EAA0BC,EAA1B,CAA6B,cAA7B,CAA6C,SAASC,CAAT,CAAY,CACrD,GAAIC,CAAAA,CAAI,CAAG,cAAED,CAAC,CAACE,MAAJ,EAAYC,IAAZ,CAAiB,MAAjB,CAAX,CACA,GAAIC,OAAO,CAACC,YAAZ,CAA0B,CACtBD,OAAO,CAACC,YAAR,CAAqB,IAArB,CAA2B,IAA3B,CAAiCJ,CAAjC,CACH,CAFD,IAEO,CACHK,QAAQ,CAACL,IAAT,CAAgBA,CACnB,CACJ,CAPD,EAQA,GAAMA,CAAAA,CAAI,CAAGM,MAAM,CAACD,QAAP,CAAgBL,IAA7B,CACA,GAAIA,CAAJ,CAAU,CACN,GAAMO,CAAAA,CAAG,CAAGC,QAAQ,CAACC,aAAT,CAAuB,oBAAqBT,CAArB,CAA4B,KAAnD,CAAZ,CACA,GAAIO,CAAJ,CAAS,CACLA,CAAG,CAACG,KAAJ,EACH,CACJ,CACJ,C,CAMKC,CAAc,CAAG,UAAM,CACzB,cAAE,MAAF,EAAUC,OAAV,CAAkB,CACdC,SAAS,CAAE,MADG,CAEdC,QAAQ,CAAE,2BAFI,CAGdC,OAAO,CAAE,OAHK,CAAlB,EAMAP,QAAQ,CAACQ,gBAAT,CAA0B,SAA1B,CAAqC,SAAAjB,CAAC,CAAI,CACtC,GAAc,QAAV,GAAAA,CAAC,CAACkB,GAAF,EAAsBlB,CAAC,CAACE,MAAF,CAASiB,OAAT,CAAiB,2BAAjB,CAA1B,CAAuE,CACnE,cAAEnB,CAAC,CAACE,MAAJ,EAAYW,OAAZ,CAAoB,MAApB,CACH,CACJ,CAJD,CAKH,C,CAMKO,CAAc,CAAG,UAAM,CACzB,cAAE,MAAF,EAAUC,OAAV,CAAkB,CACdP,SAAS,CAAE,MADG,CAEdC,QAAQ,CAAE,2BAFI,CAAlB,CAIH,C,CAEKO,CAAc,CAAG,GAAIC,UAAJ,CAAY,yBAAZ,C,CAGvB,gBAGAC,CAAI,CAACC,IAAL,GAGA3B,CAAY,GAGZc,CAAc,GAGdQ,CAAc,GAGb,GAAIM,UAAJ,EAAD,CAAeD,IAAf,GAGAE,UAAEC,EAAF,CAAKC,QAAL,CAAcC,WAAd,CAA0BC,OAA1B,CAAkCC,IAAlC,IAEAV,CAAc,CAACW,OAAf,E","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Template renderer for Moodle. Load and render Moodle templates with Mustache.\n *\n * @module theme_ilb/loader\n * @copyright 2015 Damyon Wiese <damyon@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 2.9\n */\n\nimport $ from 'jquery';\nimport * as Aria from './aria';\nimport Bootstrap from './index';\nimport Pending from 'core/pending';\nimport Scroll from './scroll';\nimport setupBootstrapPendingChecks from './pending';\n\n/**\n * Rember the last visited tabs.\n */\nconst rememberTabs = () => {\n $('a[data-toggle=\"tab\"]').on('shown.bs.tab', function(e) {\n var hash = $(e.target).attr('href');\n if (history.replaceState) {\n history.replaceState(null, null, hash);\n } else {\n location.hash = hash;\n }\n });\n const hash = window.location.hash;\n if (hash) {\n const tab = document.querySelector('.nav-link[href=\"' + hash + '\"]');\n if (tab) {\n tab.click();\n }\n }\n};\n\n/**\n * Enable all popovers\n *\n */\nconst enablePopovers = () => {\n $('body').popover({\n container: 'body',\n selector: '[data-toggle=\"popover\"]',\n trigger: 'focus',\n });\n\n document.addEventListener('keydown', e => {\n if (e.key === 'Escape' && e.target.closest('[data-toggle=\"popover\"]')) {\n $(e.target).popover('hide');\n }\n });\n};\n\n/**\n * Enable tooltips\n *\n */\nconst enableTooltips = () => {\n $('body').tooltip({\n container: 'body',\n selector: '[data-toggle=\"tooltip\"]',\n });\n};\n\nconst pendingPromise = new Pending('theme_ilb/loader:init');\n\n// Add pending promise event listeners to relevant Bootstrap custom events.\nsetupBootstrapPendingChecks();\n\n// Setup Aria helpers for Bootstrap features.\nAria.init();\n\n// Remember the last visited tabs.\nrememberTabs();\n\n// Enable all popovers.\nenablePopovers();\n\n// Enable all tooltips.\nenableTooltips();\n\n// Add scroll handling.\n(new Scroll()).init();\n\n// Disables flipping the dropdowns up and getting hidden behind the navbar.\n$.fn.dropdown.Constructor.Default.flip = false;\n\npendingPromise.resolve();\n\nexport {\n Bootstrap,\n};\n"],"file":"loader.min.js"} |
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/pending",["exports","jquery"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);function c(a,b){return h(a)||g(a,b)||e(a,b)||d()}function d(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function e(a,b){if(!a)return;if("string"==typeof a)return f(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return f(a,b)}function f(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}function g(a,b){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(a)))return;var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function h(a){if(Array.isArray(a))return a}var i={alert:[{start:"close",end:"closed"}],carousel:[{start:"slide",end:"slid"}],collapse:[{start:"hide",end:"hidden"},{start:"show",end:"shown"}],dropdown:[{start:"hide",end:"hidden"},{start:"show",end:"shown"}],modal:[{start:"hide",end:"hidden"},{start:"show",end:"shown"}],popover:[{start:"hide",end:"hidden"},{start:"show",end:"shown"}],tab:[{start:"hide",end:"hidden"},{start:"show",end:"shown"}],toast:[{start:"hide",end:"hidden"},{start:"show",end:"shown"}],tooltip:[{start:"hide",end:"hidden"},{start:"show",end:"shown"}]};a.default=function(){Object.entries(i).forEach(function(a){var d=c(a,2),e=d[0],f=d[1];f.forEach(function(a){var c="".concat(a.start,".bs.").concat(e),d="".concat(a.end,".bs.").concat(e);(0,b.default)(document.body).on(c,function(a){M.util.js_pending(d);(0,b.default)(a.target).one(d,function(){M.util.js_complete(d)})})})})};return a.default}); |
|||
//# sourceMappingURL=pending.min.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/popover",["exports","./bootstrap/popover"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"Popover",{enumerable:!0,get:function get(){return b.default}});b=function(a){return a&&a.__esModule?a:{default:a}}(b)}); |
|||
//# sourceMappingURL=popover.min.js.map
|
@ -0,0 +1 @@ |
|||
{"version":3,"sources":["../src/popover.js"],"names":[],"mappings":"oOAuBA,sD","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Backward compatibility file for the old popover.js\n *\n * @module theme_ilb/popover\n * @copyright 2020 Bas Brands <bas@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Popover from './bootstrap/popover';\n\nexport {\n Popover\n};\n"],"file":"popover.min.js"} |
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/scroll",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;function b(a,b){if(!(a instanceof b)){throw new TypeError("Cannot call a class as a function")}}function c(a,b){for(var c=0,d;c<b.length;c++){d=b[c];d.enumerable=d.enumerable||!1;d.configurable=!0;if("value"in d)d.writable=!0;Object.defineProperty(a,d.key,d)}}function d(a,b,d){if(b)c(a.prototype,b);if(d)c(a,d);return a}var e=function(){function a(){b(this,a)}d(a,[{key:"init",value:function init(){this.scrollY=0;window.addEventListener("scroll",this.scrollHandler.bind(this));return this}},{key:"getScrollPosition",value:function getScrollPosition(){return window.pageYOffset||document.documentElement.scrollTop}},{key:"scrollHandler",value:function scrollHandler(){var a=document.querySelector("body"),b=this.getScrollPosition();if(b>=window.innerHeight){a.classList.add("scrolled")}else{a.classList.remove("scrolled")}}}]);return a}();a.default=e;return a.default}); |
|||
//# sourceMappingURL=scroll.min.js.map
|
@ -0,0 +1 @@ |
|||
{"version":3,"sources":["../src/scroll.js"],"names":["MoodleScroll","scrollY","window","addEventListener","scrollHandler","bind","pageYOffset","document","documentElement","scrollTop","body","querySelector","getScrollPosition","innerHeight","classList","add","remove"],"mappings":"wcA8BqBA,CAAAA,C,yEASV,CACH,KAAKC,OAAL,CAAe,CAAf,CACAC,MAAM,CAACC,gBAAP,CAAwB,QAAxB,CAAkC,KAAKC,aAAL,CAAmBC,IAAnB,CAAwB,IAAxB,CAAlC,EACA,MAAO,KACV,C,6DASmB,CAChB,MAAOH,CAAAA,MAAM,CAACI,WAAP,EAAsBC,QAAQ,CAACC,eAAT,CAAyBC,SACzD,C,qDAQe,IACNC,CAAAA,CAAI,CAAGH,QAAQ,CAACI,aAAT,CAAuB,MAAvB,CADD,CAENV,CAAO,CAAG,KAAKW,iBAAL,EAFJ,CAGZ,GAAIX,CAAO,EAAIC,MAAM,CAACW,WAAtB,CAAmC,CAC/BH,CAAI,CAACI,SAAL,CAAeC,GAAf,CAAmB,UAAnB,CACH,CAFD,IAEO,CACHL,CAAI,CAACI,SAAL,CAAeE,MAAf,CAAsB,UAAtB,CACH,CACJ,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Manage user scroll in Moodle for future floating elements.\n *\n * @module theme_ilb/scroll\n * @copyright 2020 Ferran Recio <ferran@moodle.org>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Moodle scroll handling. For now it just handle a \"scrolled\" class\n * on the body tag but in the near future could handle more floating\n * elements like option bars, docked elements or other active elements.\n *\n * @class theme_ilb/scroll\n */\nexport default class MoodleScroll {\n\n /**\n * Initialise the scroll monitoring.\n *\n * @method init\n * @chainable\n * @return {Object} this.\n */\n init() {\n this.scrollY = 0;\n window.addEventListener(\"scroll\", this.scrollHandler.bind(this));\n return this;\n }\n\n /**\n * Add special classes to body depending on scroll position.\n *\n * @method update\n * @chainable\n * @return {Integer} current scroll position.\n */\n getScrollPosition() {\n return window.pageYOffset || document.documentElement.scrollTop;\n }\n\n /**\n * Add special classes to body depending on scroll position.\n *\n * @method update\n * @chainable\n */\n scrollHandler() {\n const body = document.querySelector('body');\n const scrollY = this.getScrollPosition();\n if (scrollY >= window.innerHeight) {\n body.classList.add('scrolled');\n } else {\n body.classList.remove('scrolled');\n }\n }\n}\n"],"file":"scroll.min.js"} |
@ -0,0 +1,2 @@ |
|||
define ("theme_ilb/toast",["exports","./bootstrap/toast"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});Object.defineProperty(a,"Toast",{enumerable:!0,get:function get(){return b.default}});b=function(a){return a&&a.__esModule?a:{default:a}}(b)}); |
|||
//# sourceMappingURL=toast.min.js.map
|
@ -0,0 +1 @@ |
|||
{"version":3,"sources":["../src/toast.js"],"names":[],"mappings":"8NAuBA,sD","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Backward compatibility file for the old toast.js\n *\n * @module theme_ilb/toast\n * @copyright 2020 Bas Brands <bas@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Toast from './bootstrap/toast';\n\nexport {\n Toast\n};\n"],"file":"toast.min.js"} |
@ -0,0 +1,282 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Enhancements to Bootstrap components for accessibility. |
|||
* |
|||
* @module theme_ilb/aria |
|||
* @copyright 2018 Damyon Wiese <damyon@moodle.com> |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
*/ |
|||
|
|||
import $ from 'jquery'; |
|||
import Pending from 'core/pending'; |
|||
|
|||
/** |
|||
* Drop downs from bootstrap don't support keyboard accessibility by default. |
|||
*/ |
|||
const dropdownFix = () => { |
|||
let focusEnd = false; |
|||
const setFocusEnd = () => { |
|||
focusEnd = true; |
|||
}; |
|||
const getFocusEnd = () => { |
|||
const result = focusEnd; |
|||
focusEnd = false; |
|||
return result; |
|||
}; |
|||
|
|||
// Special handling for "up" keyboard control.
|
|||
document.addEventListener('keydown', e => { |
|||
if (e.target.matches('[data-toggle="dropdown"]')) { |
|||
const trigger = e.key; |
|||
|
|||
// Up key opens the menu at the end.
|
|||
if (trigger == 'ArrowUp') { |
|||
// Focus the end of the menu, not the beginning.
|
|||
setFocusEnd(); |
|||
} |
|||
|
|||
// Space key or Enter key opens the menu.
|
|||
if (trigger == ' ' || trigger == 'Enter') { |
|||
// Cancel random scroll.
|
|||
e.preventDefault(); |
|||
// Open the menu instead.
|
|||
e.target.click(); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// Special handling for navigation keys when menu is open.
|
|||
const shiftFocus = element => { |
|||
const delayedFocus = pendingPromise => { |
|||
element.focus(); |
|||
pendingPromise.resolve(); |
|||
}; |
|||
setTimeout(delayedFocus, 50, new Pending('core/aria:delayed-focus')); |
|||
}; |
|||
|
|||
$('.dropdown').on('shown.bs.dropdown', e => { |
|||
// We need to focus on the first menuitem.
|
|||
const menu = e.target.querySelector('[role="menu"]'); |
|||
let menuItems = false; |
|||
let foundMenuItem = false; |
|||
|
|||
if (menu) { |
|||
menuItems = menu.querySelectorAll('[role="menuitem"]'); |
|||
} |
|||
if (menuItems && menuItems.length > 0) { |
|||
if (getFocusEnd()) { |
|||
foundMenuItem = menuItems[menuItems.length - 1]; |
|||
} else { |
|||
// The first menu entry, pretty reasonable.
|
|||
foundMenuItem = menuItems[0]; |
|||
} |
|||
} |
|||
if (foundMenuItem) { |
|||
shiftFocus(foundMenuItem); |
|||
} |
|||
}); |
|||
// Search for menu items by finding the first item that has
|
|||
// text starting with the typed character (case insensitive).
|
|||
document.addEventListener('keypress', e => { |
|||
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) { |
|||
const menu = e.target.closest('[role="menu"]'); |
|||
if (!menu) { |
|||
return; |
|||
} |
|||
const menuItems = menu.querySelectorAll('[role="menuitem"]'); |
|||
if (!menuItems) { |
|||
return; |
|||
} |
|||
|
|||
const trigger = e.key.toLowerCase(); |
|||
|
|||
for (let i = 0; i < menuItems.length; i++) { |
|||
const item = menuItems[i]; |
|||
const itemText = item.text.trim().toLowerCase(); |
|||
if (itemText.indexOf(trigger) == 0) { |
|||
shiftFocus(item); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// Keyboard navigation for arrow keys, home and end keys.
|
|||
document.addEventListener('keydown', e => { |
|||
if (e.target.matches('.dropdown [role="menu"] [role="menuitem"]')) { |
|||
const trigger = e.key; |
|||
let next = false; |
|||
const menu = e.target.closest('[role="menu"]'); |
|||
|
|||
if (!menu) { |
|||
return; |
|||
} |
|||
const menuItems = menu.querySelectorAll('[role="menuitem"]'); |
|||
if (!menuItems) { |
|||
return; |
|||
} |
|||
// Down key.
|
|||
if (trigger == 'ArrowDown') { |
|||
for (let i = 0; i < menuItems.length - 1; i++) { |
|||
if (menuItems[i] == e.target) { |
|||
next = menuItems[i + 1]; |
|||
break; |
|||
} |
|||
} |
|||
if (!next) { |
|||
// Wrap to first item.
|
|||
next = menuItems[0]; |
|||
} |
|||
|
|||
} else if (trigger == 'ArrowUp') { |
|||
// Up key.
|
|||
for (let i = 1; i < menuItems.length; i++) { |
|||
if (menuItems[i] == e.target) { |
|||
next = menuItems[i - 1]; |
|||
break; |
|||
} |
|||
} |
|||
if (!next) { |
|||
// Wrap to last item.
|
|||
next = menuItems[menuItems.length - 1]; |
|||
} |
|||
|
|||
} else if (trigger == 'Home') { |
|||
// Home key.
|
|||
next = menuItems[0]; |
|||
|
|||
} else if (trigger == 'End') { |
|||
// End key.
|
|||
next = menuItems[menuItems.length - 1]; |
|||
} |
|||
// Variable next is set if we do want to act on the keypress.
|
|||
if (next) { |
|||
e.preventDefault(); |
|||
shiftFocus(next); |
|||
} |
|||
return; |
|||
} |
|||
}); |
|||
|
|||
$('.dropdown').on('hidden.bs.dropdown', e => { |
|||
// We need to focus on the menu trigger.
|
|||
const trigger = e.target.querySelector('[data-toggle="dropdown"]'); |
|||
if (trigger) { |
|||
shiftFocus(trigger); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* After page load, focus on any element with special autofocus attribute. |
|||
*/ |
|||
const autoFocus = () => { |
|||
window.addEventListener("load", () => { |
|||
const alerts = document.querySelectorAll('[data-aria-autofocus="true"][role="alert"]'); |
|||
Array.prototype.forEach.call(alerts, autofocusElement => { |
|||
// According to the specification an role="alert" region is only read out on change to the content
|
|||
// of that region.
|
|||
autofocusElement.innerHTML += ' '; |
|||
autofocusElement.removeAttribute('data-aria-autofocus'); |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* Changes the focus to the correct tab based on the key that is pressed. |
|||
* @param {KeyboardEvent} e |
|||
*/ |
|||
const updateTabFocus = e => { |
|||
const tabList = e.target.closest('[role="tablist"]'); |
|||
const vertical = tabList.getAttribute('aria-orientation') == 'vertical'; |
|||
const rtl = window.right_to_left(); |
|||
const arrowNext = vertical ? 'ArrowDown' : (rtl ? 'ArrowLeft' : 'ArrowRight'); |
|||
const arrowPrevious = vertical ? 'ArrowUp' : (rtl ? 'ArrowRight' : 'ArrowLeft'); |
|||
const tabs = Array.prototype.filter.call( |
|||
tabList.querySelectorAll('[role="tab"]'), |
|||
tab => getComputedStyle(tab).display !== 'none'); // We only work with the visible tabs.
|
|||
|
|||
for (let i = 0; i < tabs.length; i++) { |
|||
tabs[i].index = i; |
|||
} |
|||
|
|||
switch (e.key) { |
|||
case arrowNext: |
|||
e.preventDefault(); |
|||
if (e.target.index !== undefined && tabs[e.target.index + 1]) { |
|||
tabs[e.target.index + 1].focus(); |
|||
} else { |
|||
tabs[0].focus(); |
|||
} |
|||
break; |
|||
case arrowPrevious: |
|||
e.preventDefault(); |
|||
if (e.target.index !== undefined && tabs[e.target.index - 1]) { |
|||
tabs[e.target.index - 1].focus(); |
|||
} else { |
|||
tabs[tabs.length - 1].focus(); |
|||
} |
|||
break; |
|||
case 'Home': |
|||
e.preventDefault(); |
|||
tabs[0].focus(); |
|||
break; |
|||
case 'End': |
|||
e.preventDefault(); |
|||
tabs[tabs.length - 1].focus(); |
|||
break; |
|||
case 'Enter': |
|||
case ' ': |
|||
e.preventDefault(); |
|||
$(e.target).tab('show'); |
|||
tabs.forEach(tab => { |
|||
tab.tabIndex = -1; |
|||
}); |
|||
e.target.tabIndex = 0; |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Fix accessibility issues regarding tab elements focus and their tab order in Bootstrap navs. |
|||
*/ |
|||
const tabElementFix = () => { |
|||
document.addEventListener('keydown', e => { |
|||
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter', ' '].includes(e.key)) { |
|||
if (e.target.matches('[role="tablist"] [role="tab"]')) { |
|||
updateTabFocus(e); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
document.addEventListener('click', e => { |
|||
if (e.target.matches('[role="tablist"] [role="tab"]')) { |
|||
const tabs = e.target.closest('[role="tablist"]').querySelectorAll('[role="tab"]'); |
|||
e.preventDefault(); |
|||
$(e.target).tab('show'); |
|||
tabs.forEach(tab => { |
|||
tab.tabIndex = -1; |
|||
}); |
|||
e.target.tabIndex = 0; |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
export const init = () => { |
|||
dropdownFix(); |
|||
autoFocus(); |
|||
tabElementFix(); |
|||
}; |
@ -0,0 +1,173 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): alert.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'alert' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.alert' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
|
|||
const SELECTOR_DISMISS = '[data-dismiss="alert"]' |
|||
|
|||
const EVENT_CLOSE = `close${EVENT_KEY}` |
|||
const EVENT_CLOSED = `closed${EVENT_KEY}` |
|||
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
const CLASS_NAME_ALERT = 'alert' |
|||
const CLASS_NAME_FADE = 'fade' |
|||
const CLASS_NAME_SHOW = 'show' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Alert { |
|||
constructor(element) { |
|||
this._element = element |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
close(element) { |
|||
let rootElement = this._element |
|||
if (element) { |
|||
rootElement = this._getRootElement(element) |
|||
} |
|||
|
|||
const customEvent = this._triggerCloseEvent(rootElement) |
|||
|
|||
if (customEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
this._removeElement(rootElement) |
|||
} |
|||
|
|||
dispose() { |
|||
$.removeData(this._element, DATA_KEY) |
|||
this._element = null |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getRootElement(element) { |
|||
const selector = Util.getSelectorFromElement(element) |
|||
let parent = false |
|||
|
|||
if (selector) { |
|||
parent = document.querySelector(selector) |
|||
} |
|||
|
|||
if (!parent) { |
|||
parent = $(element).closest(`.${CLASS_NAME_ALERT}`)[0] |
|||
} |
|||
|
|||
return parent |
|||
} |
|||
|
|||
_triggerCloseEvent(element) { |
|||
const closeEvent = $.Event(EVENT_CLOSE) |
|||
|
|||
$(element).trigger(closeEvent) |
|||
return closeEvent |
|||
} |
|||
|
|||
_removeElement(element) { |
|||
$(element).removeClass(CLASS_NAME_SHOW) |
|||
|
|||
if (!$(element).hasClass(CLASS_NAME_FADE)) { |
|||
this._destroyElement(element) |
|||
return |
|||
} |
|||
|
|||
const transitionDuration = Util.getTransitionDurationFromElement(element) |
|||
|
|||
$(element) |
|||
.one(Util.TRANSITION_END, event => this._destroyElement(element, event)) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} |
|||
|
|||
_destroyElement(element) { |
|||
$(element) |
|||
.detach() |
|||
.trigger(EVENT_CLOSED) |
|||
.remove() |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
const $element = $(this) |
|||
let data = $element.data(DATA_KEY) |
|||
|
|||
if (!data) { |
|||
data = new Alert(this) |
|||
$element.data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (config === 'close') { |
|||
data[config](this) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
static _handleDismiss(alertInstance) { |
|||
return function (event) { |
|||
if (event) { |
|||
event.preventDefault() |
|||
} |
|||
|
|||
alertInstance.close(this) |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(document).on( |
|||
EVENT_CLICK_DATA_API, |
|||
SELECTOR_DISMISS, |
|||
Alert._handleDismiss(new Alert()) |
|||
) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Alert._jQueryInterface |
|||
$.fn[NAME].Constructor = Alert |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Alert._jQueryInterface |
|||
} |
|||
|
|||
export default Alert |
@ -0,0 +1,209 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): button.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'button' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.button' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
|
|||
const CLASS_NAME_ACTIVE = 'active' |
|||
const CLASS_NAME_BUTTON = 'btn' |
|||
const CLASS_NAME_FOCUS = 'focus' |
|||
|
|||
const SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^="button"]' |
|||
const SELECTOR_DATA_TOGGLES = '[data-toggle="buttons"]' |
|||
const SELECTOR_DATA_TOGGLE = '[data-toggle="button"]' |
|||
const SELECTOR_DATA_TOGGLES_BUTTONS = '[data-toggle="buttons"] .btn' |
|||
const SELECTOR_INPUT = 'input:not([type="hidden"])' |
|||
const SELECTOR_ACTIVE = '.active' |
|||
const SELECTOR_BUTTON = '.btn' |
|||
|
|||
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` |
|||
const EVENT_FOCUS_BLUR_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY} ` + |
|||
`blur${EVENT_KEY}${DATA_API_KEY}` |
|||
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Button { |
|||
constructor(element) { |
|||
this._element = element |
|||
this.shouldAvoidTriggerChange = false |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
toggle() { |
|||
let triggerChangeEvent = true |
|||
let addAriaPressed = true |
|||
const rootElement = $(this._element).closest(SELECTOR_DATA_TOGGLES)[0] |
|||
|
|||
if (rootElement) { |
|||
const input = this._element.querySelector(SELECTOR_INPUT) |
|||
|
|||
if (input) { |
|||
if (input.type === 'radio') { |
|||
if (input.checked && this._element.classList.contains(CLASS_NAME_ACTIVE)) { |
|||
triggerChangeEvent = false |
|||
} else { |
|||
const activeElement = rootElement.querySelector(SELECTOR_ACTIVE) |
|||
|
|||
if (activeElement) { |
|||
$(activeElement).removeClass(CLASS_NAME_ACTIVE) |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (triggerChangeEvent) { |
|||
// if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input
|
|||
if (input.type === 'checkbox' || input.type === 'radio') { |
|||
input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE) |
|||
} |
|||
|
|||
if (!this.shouldAvoidTriggerChange) { |
|||
$(input).trigger('change') |
|||
} |
|||
} |
|||
|
|||
input.focus() |
|||
addAriaPressed = false |
|||
} |
|||
} |
|||
|
|||
if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) { |
|||
if (addAriaPressed) { |
|||
this._element.setAttribute('aria-pressed', !this._element.classList.contains(CLASS_NAME_ACTIVE)) |
|||
} |
|||
|
|||
if (triggerChangeEvent) { |
|||
$(this._element).toggleClass(CLASS_NAME_ACTIVE) |
|||
} |
|||
} |
|||
} |
|||
|
|||
dispose() { |
|||
$.removeData(this._element, DATA_KEY) |
|||
this._element = null |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config, avoidTriggerChange) { |
|||
return this.each(function () { |
|||
const $element = $(this) |
|||
let data = $element.data(DATA_KEY) |
|||
|
|||
if (!data) { |
|||
data = new Button(this) |
|||
$element.data(DATA_KEY, data) |
|||
} |
|||
|
|||
data.shouldAvoidTriggerChange = avoidTriggerChange |
|||
|
|||
if (config === 'toggle') { |
|||
data[config]() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(document) |
|||
.on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => { |
|||
let button = event.target |
|||
const initialButton = button |
|||
|
|||
if (!$(button).hasClass(CLASS_NAME_BUTTON)) { |
|||
button = $(button).closest(SELECTOR_BUTTON)[0] |
|||
} |
|||
|
|||
if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) { |
|||
event.preventDefault() // work around Firefox bug #1540995
|
|||
} else { |
|||
const inputBtn = button.querySelector(SELECTOR_INPUT) |
|||
|
|||
if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) { |
|||
event.preventDefault() // work around Firefox bug #1540995
|
|||
return |
|||
} |
|||
|
|||
if (initialButton.tagName === 'INPUT' || button.tagName !== 'LABEL') { |
|||
Button._jQueryInterface.call($(button), 'toggle', initialButton.tagName === 'INPUT') |
|||
} |
|||
} |
|||
}) |
|||
.on(EVENT_FOCUS_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => { |
|||
const button = $(event.target).closest(SELECTOR_BUTTON)[0] |
|||
$(button).toggleClass(CLASS_NAME_FOCUS, /^focus(in)?$/.test(event.type)) |
|||
}) |
|||
|
|||
$(window).on(EVENT_LOAD_DATA_API, () => { |
|||
// ensure correct active class is set to match the controls' actual values/states
|
|||
|
|||
// find all checkboxes/readio buttons inside data-toggle groups
|
|||
let buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLES_BUTTONS)) |
|||
for (let i = 0, len = buttons.length; i < len; i++) { |
|||
const button = buttons[i] |
|||
const input = button.querySelector(SELECTOR_INPUT) |
|||
if (input.checked || input.hasAttribute('checked')) { |
|||
button.classList.add(CLASS_NAME_ACTIVE) |
|||
} else { |
|||
button.classList.remove(CLASS_NAME_ACTIVE) |
|||
} |
|||
} |
|||
|
|||
// find all button toggles
|
|||
buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE)) |
|||
for (let i = 0, len = buttons.length; i < len; i++) { |
|||
const button = buttons[i] |
|||
if (button.getAttribute('aria-pressed') === 'true') { |
|||
button.classList.add(CLASS_NAME_ACTIVE) |
|||
} else { |
|||
button.classList.remove(CLASS_NAME_ACTIVE) |
|||
} |
|||
} |
|||
}) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Button._jQueryInterface |
|||
$.fn[NAME].Constructor = Button |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Button._jQueryInterface |
|||
} |
|||
|
|||
export default Button |
@ -0,0 +1,613 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): carousel.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'carousel' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.carousel' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key
|
|||
const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key
|
|||
const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch
|
|||
const SWIPE_THRESHOLD = 40 |
|||
|
|||
const Default = { |
|||
interval: 5000, |
|||
keyboard: true, |
|||
slide: false, |
|||
pause: 'hover', |
|||
wrap: true, |
|||
touch: true |
|||
} |
|||
|
|||
const DefaultType = { |
|||
interval: '(number|boolean)', |
|||
keyboard: 'boolean', |
|||
slide: '(boolean|string)', |
|||
pause: '(string|boolean)', |
|||
wrap: 'boolean', |
|||
touch: 'boolean' |
|||
} |
|||
|
|||
const DIRECTION_NEXT = 'next' |
|||
const DIRECTION_PREV = 'prev' |
|||
const DIRECTION_LEFT = 'left' |
|||
const DIRECTION_RIGHT = 'right' |
|||
|
|||
const EVENT_SLIDE = `slide${EVENT_KEY}` |
|||
const EVENT_SLID = `slid${EVENT_KEY}` |
|||
const EVENT_KEYDOWN = `keydown${EVENT_KEY}` |
|||
const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}` |
|||
const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}` |
|||
const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}` |
|||
const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}` |
|||
const EVENT_TOUCHEND = `touchend${EVENT_KEY}` |
|||
const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}` |
|||
const EVENT_POINTERUP = `pointerup${EVENT_KEY}` |
|||
const EVENT_DRAG_START = `dragstart${EVENT_KEY}` |
|||
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` |
|||
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
const CLASS_NAME_CAROUSEL = 'carousel' |
|||
const CLASS_NAME_ACTIVE = 'active' |
|||
const CLASS_NAME_SLIDE = 'slide' |
|||
const CLASS_NAME_RIGHT = 'carousel-item-right' |
|||
const CLASS_NAME_LEFT = 'carousel-item-left' |
|||
const CLASS_NAME_NEXT = 'carousel-item-next' |
|||
const CLASS_NAME_PREV = 'carousel-item-prev' |
|||
const CLASS_NAME_POINTER_EVENT = 'pointer-event' |
|||
|
|||
const SELECTOR_ACTIVE = '.active' |
|||
const SELECTOR_ACTIVE_ITEM = '.active.carousel-item' |
|||
const SELECTOR_ITEM = '.carousel-item' |
|||
const SELECTOR_ITEM_IMG = '.carousel-item img' |
|||
const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev' |
|||
const SELECTOR_INDICATORS = '.carousel-indicators' |
|||
const SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]' |
|||
const SELECTOR_DATA_RIDE = '[data-ride="carousel"]' |
|||
|
|||
const PointerType = { |
|||
TOUCH: 'touch', |
|||
PEN: 'pen' |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
class Carousel { |
|||
constructor(element, config) { |
|||
this._items = null |
|||
this._interval = null |
|||
this._activeElement = null |
|||
this._isPaused = false |
|||
this._isSliding = false |
|||
this.touchTimeout = null |
|||
this.touchStartX = 0 |
|||
this.touchDeltaX = 0 |
|||
|
|||
this._config = this._getConfig(config) |
|||
this._element = element |
|||
this._indicatorsElement = this._element.querySelector(SELECTOR_INDICATORS) |
|||
this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 |
|||
this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent) |
|||
|
|||
this._addEventListeners() |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
next() { |
|||
if (!this._isSliding) { |
|||
this._slide(DIRECTION_NEXT) |
|||
} |
|||
} |
|||
|
|||
nextWhenVisible() { |
|||
const $element = $(this._element) |
|||
// Don't call next when the page isn't visible
|
|||
// or the carousel or its parent isn't visible
|
|||
if (!document.hidden && |
|||
($element.is(':visible') && $element.css('visibility') !== 'hidden')) { |
|||
this.next() |
|||
} |
|||
} |
|||
|
|||
prev() { |
|||
if (!this._isSliding) { |
|||
this._slide(DIRECTION_PREV) |
|||
} |
|||
} |
|||
|
|||
pause(event) { |
|||
if (!event) { |
|||
this._isPaused = true |
|||
} |
|||
|
|||
if (this._element.querySelector(SELECTOR_NEXT_PREV)) { |
|||
Util.triggerTransitionEnd(this._element) |
|||
this.cycle(true) |
|||
} |
|||
|
|||
clearInterval(this._interval) |
|||
this._interval = null |
|||
} |
|||
|
|||
cycle(event) { |
|||
if (!event) { |
|||
this._isPaused = false |
|||
} |
|||
|
|||
if (this._interval) { |
|||
clearInterval(this._interval) |
|||
this._interval = null |
|||
} |
|||
|
|||
if (this._config.interval && !this._isPaused) { |
|||
this._updateInterval() |
|||
|
|||
this._interval = setInterval( |
|||
(document.visibilityState ? this.nextWhenVisible : this.next).bind(this), |
|||
this._config.interval |
|||
) |
|||
} |
|||
} |
|||
|
|||
to(index) { |
|||
this._activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM) |
|||
|
|||
const activeIndex = this._getItemIndex(this._activeElement) |
|||
|
|||
if (index > this._items.length - 1 || index < 0) { |
|||
return |
|||
} |
|||
|
|||
if (this._isSliding) { |
|||
$(this._element).one(EVENT_SLID, () => this.to(index)) |
|||
return |
|||
} |
|||
|
|||
if (activeIndex === index) { |
|||
this.pause() |
|||
this.cycle() |
|||
return |
|||
} |
|||
|
|||
const direction = index > activeIndex ? |
|||
DIRECTION_NEXT : |
|||
DIRECTION_PREV |
|||
|
|||
this._slide(direction, this._items[index]) |
|||
} |
|||
|
|||
dispose() { |
|||
$(this._element).off(EVENT_KEY) |
|||
$.removeData(this._element, DATA_KEY) |
|||
|
|||
this._items = null |
|||
this._config = null |
|||
this._element = null |
|||
this._interval = null |
|||
this._isPaused = null |
|||
this._isSliding = null |
|||
this._activeElement = null |
|||
this._indicatorsElement = null |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getConfig(config) { |
|||
config = { |
|||
...Default, |
|||
...config |
|||
} |
|||
Util.typeCheckConfig(NAME, config, DefaultType) |
|||
return config |
|||
} |
|||
|
|||
_handleSwipe() { |
|||
const absDeltax = Math.abs(this.touchDeltaX) |
|||
|
|||
if (absDeltax <= SWIPE_THRESHOLD) { |
|||
return |
|||
} |
|||
|
|||
const direction = absDeltax / this.touchDeltaX |
|||
|
|||
this.touchDeltaX = 0 |
|||
|
|||
// swipe left
|
|||
if (direction > 0) { |
|||
this.prev() |
|||
} |
|||
|
|||
// swipe right
|
|||
if (direction < 0) { |
|||
this.next() |
|||
} |
|||
} |
|||
|
|||
_addEventListeners() { |
|||
if (this._config.keyboard) { |
|||
$(this._element).on(EVENT_KEYDOWN, event => this._keydown(event)) |
|||
} |
|||
|
|||
if (this._config.pause === 'hover') { |
|||
$(this._element) |
|||
.on(EVENT_MOUSEENTER, event => this.pause(event)) |
|||
.on(EVENT_MOUSELEAVE, event => this.cycle(event)) |
|||
} |
|||
|
|||
if (this._config.touch) { |
|||
this._addTouchEventListeners() |
|||
} |
|||
} |
|||
|
|||
_addTouchEventListeners() { |
|||
if (!this._touchSupported) { |
|||
return |
|||
} |
|||
|
|||
const start = event => { |
|||
if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { |
|||
this.touchStartX = event.originalEvent.clientX |
|||
} else if (!this._pointerEvent) { |
|||
this.touchStartX = event.originalEvent.touches[0].clientX |
|||
} |
|||
} |
|||
|
|||
const move = event => { |
|||
// ensure swiping with one touch and not pinching
|
|||
if (event.originalEvent.touches && event.originalEvent.touches.length > 1) { |
|||
this.touchDeltaX = 0 |
|||
} else { |
|||
this.touchDeltaX = event.originalEvent.touches[0].clientX - this.touchStartX |
|||
} |
|||
} |
|||
|
|||
const end = event => { |
|||
if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { |
|||
this.touchDeltaX = event.originalEvent.clientX - this.touchStartX |
|||
} |
|||
|
|||
this._handleSwipe() |
|||
if (this._config.pause === 'hover') { |
|||
// If it's a touch-enabled device, mouseenter/leave are fired as
|
|||
// part of the mouse compatibility events on first tap - the carousel
|
|||
// would stop cycling until user tapped out of it;
|
|||
// here, we listen for touchend, explicitly pause the carousel
|
|||
// (as if it's the second time we tap on it, mouseenter compat event
|
|||
// is NOT fired) and after a timeout (to allow for mouse compatibility
|
|||
// events to fire) we explicitly restart cycling
|
|||
|
|||
this.pause() |
|||
if (this.touchTimeout) { |
|||
clearTimeout(this.touchTimeout) |
|||
} |
|||
|
|||
this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval) |
|||
} |
|||
} |
|||
|
|||
$(this._element.querySelectorAll(SELECTOR_ITEM_IMG)) |
|||
.on(EVENT_DRAG_START, e => e.preventDefault()) |
|||
|
|||
if (this._pointerEvent) { |
|||
$(this._element).on(EVENT_POINTERDOWN, event => start(event)) |
|||
$(this._element).on(EVENT_POINTERUP, event => end(event)) |
|||
|
|||
this._element.classList.add(CLASS_NAME_POINTER_EVENT) |
|||
} else { |
|||
$(this._element).on(EVENT_TOUCHSTART, event => start(event)) |
|||
$(this._element).on(EVENT_TOUCHMOVE, event => move(event)) |
|||
$(this._element).on(EVENT_TOUCHEND, event => end(event)) |
|||
} |
|||
} |
|||
|
|||
_keydown(event) { |
|||
if (/input|textarea/i.test(event.target.tagName)) { |
|||
return |
|||
} |
|||
|
|||
switch (event.which) { |
|||
case ARROW_LEFT_KEYCODE: |
|||
event.preventDefault() |
|||
this.prev() |
|||
break |
|||
case ARROW_RIGHT_KEYCODE: |
|||
event.preventDefault() |
|||
this.next() |
|||
break |
|||
default: |
|||
} |
|||
} |
|||
|
|||
_getItemIndex(element) { |
|||
this._items = element && element.parentNode ? |
|||
[].slice.call(element.parentNode.querySelectorAll(SELECTOR_ITEM)) : |
|||
[] |
|||
return this._items.indexOf(element) |
|||
} |
|||
|
|||
_getItemByDirection(direction, activeElement) { |
|||
const isNextDirection = direction === DIRECTION_NEXT |
|||
const isPrevDirection = direction === DIRECTION_PREV |
|||
const activeIndex = this._getItemIndex(activeElement) |
|||
const lastItemIndex = this._items.length - 1 |
|||
const isGoingToWrap = isPrevDirection && activeIndex === 0 || |
|||
isNextDirection && activeIndex === lastItemIndex |
|||
|
|||
if (isGoingToWrap && !this._config.wrap) { |
|||
return activeElement |
|||
} |
|||
|
|||
const delta = direction === DIRECTION_PREV ? -1 : 1 |
|||
const itemIndex = (activeIndex + delta) % this._items.length |
|||
|
|||
return itemIndex === -1 ? |
|||
this._items[this._items.length - 1] : this._items[itemIndex] |
|||
} |
|||
|
|||
_triggerSlideEvent(relatedTarget, eventDirectionName) { |
|||
const targetIndex = this._getItemIndex(relatedTarget) |
|||
const fromIndex = this._getItemIndex(this._element.querySelector(SELECTOR_ACTIVE_ITEM)) |
|||
const slideEvent = $.Event(EVENT_SLIDE, { |
|||
relatedTarget, |
|||
direction: eventDirectionName, |
|||
from: fromIndex, |
|||
to: targetIndex |
|||
}) |
|||
|
|||
$(this._element).trigger(slideEvent) |
|||
|
|||
return slideEvent |
|||
} |
|||
|
|||
_setActiveIndicatorElement(element) { |
|||
if (this._indicatorsElement) { |
|||
const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(SELECTOR_ACTIVE)) |
|||
$(indicators).removeClass(CLASS_NAME_ACTIVE) |
|||
|
|||
const nextIndicator = this._indicatorsElement.children[ |
|||
this._getItemIndex(element) |
|||
] |
|||
|
|||
if (nextIndicator) { |
|||
$(nextIndicator).addClass(CLASS_NAME_ACTIVE) |
|||
} |
|||
} |
|||
} |
|||
|
|||
_updateInterval() { |
|||
const element = this._activeElement || this._element.querySelector(SELECTOR_ACTIVE_ITEM) |
|||
|
|||
if (!element) { |
|||
return |
|||
} |
|||
|
|||
const elementInterval = parseInt(element.getAttribute('data-interval'), 10) |
|||
|
|||
if (elementInterval) { |
|||
this._config.defaultInterval = this._config.defaultInterval || this._config.interval |
|||
this._config.interval = elementInterval |
|||
} else { |
|||
this._config.interval = this._config.defaultInterval || this._config.interval |
|||
} |
|||
} |
|||
|
|||
_slide(direction, element) { |
|||
const activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM) |
|||
const activeElementIndex = this._getItemIndex(activeElement) |
|||
const nextElement = element || activeElement && |
|||
this._getItemByDirection(direction, activeElement) |
|||
const nextElementIndex = this._getItemIndex(nextElement) |
|||
const isCycling = Boolean(this._interval) |
|||
|
|||
let directionalClassName |
|||
let orderClassName |
|||
let eventDirectionName |
|||
|
|||
if (direction === DIRECTION_NEXT) { |
|||
directionalClassName = CLASS_NAME_LEFT |
|||
orderClassName = CLASS_NAME_NEXT |
|||
eventDirectionName = DIRECTION_LEFT |
|||
} else { |
|||
directionalClassName = CLASS_NAME_RIGHT |
|||
orderClassName = CLASS_NAME_PREV |
|||
eventDirectionName = DIRECTION_RIGHT |
|||
} |
|||
|
|||
if (nextElement && $(nextElement).hasClass(CLASS_NAME_ACTIVE)) { |
|||
this._isSliding = false |
|||
return |
|||
} |
|||
|
|||
const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) |
|||
if (slideEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
if (!activeElement || !nextElement) { |
|||
// Some weirdness is happening, so we bail
|
|||
return |
|||
} |
|||
|
|||
this._isSliding = true |
|||
|
|||
if (isCycling) { |
|||
this.pause() |
|||
} |
|||
|
|||
this._setActiveIndicatorElement(nextElement) |
|||
this._activeElement = nextElement |
|||
|
|||
const slidEvent = $.Event(EVENT_SLID, { |
|||
relatedTarget: nextElement, |
|||
direction: eventDirectionName, |
|||
from: activeElementIndex, |
|||
to: nextElementIndex |
|||
}) |
|||
|
|||
if ($(this._element).hasClass(CLASS_NAME_SLIDE)) { |
|||
$(nextElement).addClass(orderClassName) |
|||
|
|||
Util.reflow(nextElement) |
|||
|
|||
$(activeElement).addClass(directionalClassName) |
|||
$(nextElement).addClass(directionalClassName) |
|||
|
|||
const transitionDuration = Util.getTransitionDurationFromElement(activeElement) |
|||
|
|||
$(activeElement) |
|||
.one(Util.TRANSITION_END, () => { |
|||
$(nextElement) |
|||
.removeClass(`${directionalClassName} ${orderClassName}`) |
|||
.addClass(CLASS_NAME_ACTIVE) |
|||
|
|||
$(activeElement).removeClass(`${CLASS_NAME_ACTIVE} ${orderClassName} ${directionalClassName}`) |
|||
|
|||
this._isSliding = false |
|||
|
|||
setTimeout(() => $(this._element).trigger(slidEvent), 0) |
|||
}) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
$(activeElement).removeClass(CLASS_NAME_ACTIVE) |
|||
$(nextElement).addClass(CLASS_NAME_ACTIVE) |
|||
|
|||
this._isSliding = false |
|||
$(this._element).trigger(slidEvent) |
|||
} |
|||
|
|||
if (isCycling) { |
|||
this.cycle() |
|||
} |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
let data = $(this).data(DATA_KEY) |
|||
let _config = { |
|||
...Default, |
|||
...$(this).data() |
|||
} |
|||
|
|||
if (typeof config === 'object') { |
|||
_config = { |
|||
..._config, |
|||
...config |
|||
} |
|||
} |
|||
|
|||
const action = typeof config === 'string' ? config : _config.slide |
|||
|
|||
if (!data) { |
|||
data = new Carousel(this, _config) |
|||
$(this).data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'number') { |
|||
data.to(config) |
|||
} else if (typeof action === 'string') { |
|||
if (typeof data[action] === 'undefined') { |
|||
throw new TypeError(`No method named "${action}"`) |
|||
} |
|||
|
|||
data[action]() |
|||
} else if (_config.interval && _config.ride) { |
|||
data.pause() |
|||
data.cycle() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
static _dataApiClickHandler(event) { |
|||
const selector = Util.getSelectorFromElement(this) |
|||
|
|||
if (!selector) { |
|||
return |
|||
} |
|||
|
|||
const target = $(selector)[0] |
|||
|
|||
if (!target || !$(target).hasClass(CLASS_NAME_CAROUSEL)) { |
|||
return |
|||
} |
|||
|
|||
const config = { |
|||
...$(target).data(), |
|||
...$(this).data() |
|||
} |
|||
const slideIndex = this.getAttribute('data-slide-to') |
|||
|
|||
if (slideIndex) { |
|||
config.interval = false |
|||
} |
|||
|
|||
Carousel._jQueryInterface.call($(target), config) |
|||
|
|||
if (slideIndex) { |
|||
$(target).data(DATA_KEY).to(slideIndex) |
|||
} |
|||
|
|||
event.preventDefault() |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel._dataApiClickHandler) |
|||
|
|||
$(window).on(EVENT_LOAD_DATA_API, () => { |
|||
const carousels = [].slice.call(document.querySelectorAll(SELECTOR_DATA_RIDE)) |
|||
for (let i = 0, len = carousels.length; i < len; i++) { |
|||
const $carousel = $(carousels[i]) |
|||
Carousel._jQueryInterface.call($carousel, $carousel.data()) |
|||
} |
|||
}) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Carousel._jQueryInterface |
|||
$.fn[NAME].Constructor = Carousel |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Carousel._jQueryInterface |
|||
} |
|||
|
|||
export default Carousel |
@ -0,0 +1,392 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): collapse.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'collapse' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.collapse' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
|
|||
const Default = { |
|||
toggle: true, |
|||
parent: '' |
|||
} |
|||
|
|||
const DefaultType = { |
|||
toggle: 'boolean', |
|||
parent: '(string|element)' |
|||
} |
|||
|
|||
const EVENT_SHOW = `show${EVENT_KEY}` |
|||
const EVENT_SHOWN = `shown${EVENT_KEY}` |
|||
const EVENT_HIDE = `hide${EVENT_KEY}` |
|||
const EVENT_HIDDEN = `hidden${EVENT_KEY}` |
|||
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
const CLASS_NAME_SHOW = 'show' |
|||
const CLASS_NAME_COLLAPSE = 'collapse' |
|||
const CLASS_NAME_COLLAPSING = 'collapsing' |
|||
const CLASS_NAME_COLLAPSED = 'collapsed' |
|||
|
|||
const DIMENSION_WIDTH = 'width' |
|||
const DIMENSION_HEIGHT = 'height' |
|||
|
|||
const SELECTOR_ACTIVES = '.show, .collapsing' |
|||
const SELECTOR_DATA_TOGGLE = '[data-toggle="collapse"]' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Collapse { |
|||
constructor(element, config) { |
|||
this._isTransitioning = false |
|||
this._element = element |
|||
this._config = this._getConfig(config) |
|||
this._triggerArray = [].slice.call(document.querySelectorAll( |
|||
`[data-toggle="collapse"][href="#${element.id}"],` + |
|||
`[data-toggle="collapse"][data-target="#${element.id}"]` |
|||
)) |
|||
|
|||
const toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE)) |
|||
for (let i = 0, len = toggleList.length; i < len; i++) { |
|||
const elem = toggleList[i] |
|||
const selector = Util.getSelectorFromElement(elem) |
|||
const filterElement = [].slice.call(document.querySelectorAll(selector)) |
|||
.filter(foundElem => foundElem === element) |
|||
|
|||
if (selector !== null && filterElement.length > 0) { |
|||
this._selector = selector |
|||
this._triggerArray.push(elem) |
|||
} |
|||
} |
|||
|
|||
this._parent = this._config.parent ? this._getParent() : null |
|||
|
|||
if (!this._config.parent) { |
|||
this._addAriaAndCollapsedClass(this._element, this._triggerArray) |
|||
} |
|||
|
|||
if (this._config.toggle) { |
|||
this.toggle() |
|||
} |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
toggle() { |
|||
if ($(this._element).hasClass(CLASS_NAME_SHOW)) { |
|||
this.hide() |
|||
} else { |
|||
this.show() |
|||
} |
|||
} |
|||
|
|||
show() { |
|||
if (this._isTransitioning || |
|||
$(this._element).hasClass(CLASS_NAME_SHOW)) { |
|||
return |
|||
} |
|||
|
|||
let actives |
|||
let activesData |
|||
|
|||
if (this._parent) { |
|||
actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES)) |
|||
.filter(elem => { |
|||
if (typeof this._config.parent === 'string') { |
|||
return elem.getAttribute('data-parent') === this._config.parent |
|||
} |
|||
|
|||
return elem.classList.contains(CLASS_NAME_COLLAPSE) |
|||
}) |
|||
|
|||
if (actives.length === 0) { |
|||
actives = null |
|||
} |
|||
} |
|||
|
|||
if (actives) { |
|||
activesData = $(actives).not(this._selector).data(DATA_KEY) |
|||
if (activesData && activesData._isTransitioning) { |
|||
return |
|||
} |
|||
} |
|||
|
|||
const startEvent = $.Event(EVENT_SHOW) |
|||
$(this._element).trigger(startEvent) |
|||
if (startEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
if (actives) { |
|||
Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide') |
|||
if (!activesData) { |
|||
$(actives).data(DATA_KEY, null) |
|||
} |
|||
} |
|||
|
|||
const dimension = this._getDimension() |
|||
|
|||
$(this._element) |
|||
.removeClass(CLASS_NAME_COLLAPSE) |
|||
.addClass(CLASS_NAME_COLLAPSING) |
|||
|
|||
this._element.style[dimension] = 0 |
|||
|
|||
if (this._triggerArray.length) { |
|||
$(this._triggerArray) |
|||
.removeClass(CLASS_NAME_COLLAPSED) |
|||
.attr('aria-expanded', true) |
|||
} |
|||
|
|||
this.setTransitioning(true) |
|||
|
|||
const complete = () => { |
|||
$(this._element) |
|||
.removeClass(CLASS_NAME_COLLAPSING) |
|||
.addClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`) |
|||
|
|||
this._element.style[dimension] = '' |
|||
|
|||
this.setTransitioning(false) |
|||
|
|||
$(this._element).trigger(EVENT_SHOWN) |
|||
} |
|||
|
|||
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1) |
|||
const scrollSize = `scroll${capitalizedDimension}` |
|||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) |
|||
|
|||
$(this._element) |
|||
.one(Util.TRANSITION_END, complete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
|
|||
this._element.style[dimension] = `${this._element[scrollSize]}px` |
|||
} |
|||
|
|||
hide() { |
|||
if (this._isTransitioning || |
|||
!$(this._element).hasClass(CLASS_NAME_SHOW)) { |
|||
return |
|||
} |
|||
|
|||
const startEvent = $.Event(EVENT_HIDE) |
|||
$(this._element).trigger(startEvent) |
|||
if (startEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
const dimension = this._getDimension() |
|||
|
|||
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px` |
|||
|
|||
Util.reflow(this._element) |
|||
|
|||
$(this._element) |
|||
.addClass(CLASS_NAME_COLLAPSING) |
|||
.removeClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`) |
|||
|
|||
const triggerArrayLength = this._triggerArray.length |
|||
if (triggerArrayLength > 0) { |
|||
for (let i = 0; i < triggerArrayLength; i++) { |
|||
const trigger = this._triggerArray[i] |
|||
const selector = Util.getSelectorFromElement(trigger) |
|||
|
|||
if (selector !== null) { |
|||
const $elem = $([].slice.call(document.querySelectorAll(selector))) |
|||
if (!$elem.hasClass(CLASS_NAME_SHOW)) { |
|||
$(trigger).addClass(CLASS_NAME_COLLAPSED) |
|||
.attr('aria-expanded', false) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
this.setTransitioning(true) |
|||
|
|||
const complete = () => { |
|||
this.setTransitioning(false) |
|||
$(this._element) |
|||
.removeClass(CLASS_NAME_COLLAPSING) |
|||
.addClass(CLASS_NAME_COLLAPSE) |
|||
.trigger(EVENT_HIDDEN) |
|||
} |
|||
|
|||
this._element.style[dimension] = '' |
|||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) |
|||
|
|||
$(this._element) |
|||
.one(Util.TRANSITION_END, complete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} |
|||
|
|||
setTransitioning(isTransitioning) { |
|||
this._isTransitioning = isTransitioning |
|||
} |
|||
|
|||
dispose() { |
|||
$.removeData(this._element, DATA_KEY) |
|||
|
|||
this._config = null |
|||
this._parent = null |
|||
this._element = null |
|||
this._triggerArray = null |
|||
this._isTransitioning = null |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getConfig(config) { |
|||
config = { |
|||
...Default, |
|||
...config |
|||
} |
|||
config.toggle = Boolean(config.toggle) // Coerce string values
|
|||
Util.typeCheckConfig(NAME, config, DefaultType) |
|||
return config |
|||
} |
|||
|
|||
_getDimension() { |
|||
const hasWidth = $(this._element).hasClass(DIMENSION_WIDTH) |
|||
return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT |
|||
} |
|||
|
|||
_getParent() { |
|||
let parent |
|||
|
|||
if (Util.isElement(this._config.parent)) { |
|||
parent = this._config.parent |
|||
|
|||
// It's a jQuery object
|
|||
if (typeof this._config.parent.jquery !== 'undefined') { |
|||
parent = this._config.parent[0] |
|||
} |
|||
} else { |
|||
parent = document.querySelector(this._config.parent) |
|||
} |
|||
|
|||
const selector = `[data-toggle="collapse"][data-parent="${this._config.parent}"]` |
|||
const children = [].slice.call(parent.querySelectorAll(selector)) |
|||
|
|||
$(children).each((i, element) => { |
|||
this._addAriaAndCollapsedClass( |
|||
Collapse._getTargetFromElement(element), |
|||
[element] |
|||
) |
|||
}) |
|||
|
|||
return parent |
|||
} |
|||
|
|||
_addAriaAndCollapsedClass(element, triggerArray) { |
|||
const isOpen = $(element).hasClass(CLASS_NAME_SHOW) |
|||
|
|||
if (triggerArray.length) { |
|||
$(triggerArray) |
|||
.toggleClass(CLASS_NAME_COLLAPSED, !isOpen) |
|||
.attr('aria-expanded', isOpen) |
|||
} |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _getTargetFromElement(element) { |
|||
const selector = Util.getSelectorFromElement(element) |
|||
return selector ? document.querySelector(selector) : null |
|||
} |
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
const $element = $(this) |
|||
let data = $element.data(DATA_KEY) |
|||
const _config = { |
|||
...Default, |
|||
...$element.data(), |
|||
...(typeof config === 'object' && config ? config : {}) |
|||
} |
|||
|
|||
if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) { |
|||
_config.toggle = false |
|||
} |
|||
|
|||
if (!data) { |
|||
data = new Collapse(this, _config) |
|||
$element.data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config]() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { |
|||
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element
|
|||
if (event.currentTarget.tagName === 'A') { |
|||
event.preventDefault() |
|||
} |
|||
|
|||
const $trigger = $(this) |
|||
const selector = Util.getSelectorFromElement(this) |
|||
const selectors = [].slice.call(document.querySelectorAll(selector)) |
|||
|
|||
$(selectors).each(function () { |
|||
const $target = $(this) |
|||
const data = $target.data(DATA_KEY) |
|||
const config = data ? 'toggle' : $trigger.data() |
|||
Collapse._jQueryInterface.call($target, config) |
|||
}) |
|||
}) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Collapse._jQueryInterface |
|||
$.fn[NAME].Constructor = Collapse |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Collapse._jQueryInterface |
|||
} |
|||
|
|||
export default Collapse |
@ -0,0 +1,538 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): dropdown.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Popper from 'core/popper' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'dropdown' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.dropdown' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
|
|||
const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key
|
|||
const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key
|
|||
const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key
|
|||
const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key
|
|||
const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)
|
|||
const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`) |
|||
|
|||
const EVENT_HIDE = `hide${EVENT_KEY}` |
|||
const EVENT_HIDDEN = `hidden${EVENT_KEY}` |
|||
const EVENT_SHOW = `show${EVENT_KEY}` |
|||
const EVENT_SHOWN = `shown${EVENT_KEY}` |
|||
const EVENT_CLICK = `click${EVENT_KEY}` |
|||
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` |
|||
const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}` |
|||
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
const CLASS_NAME_DISABLED = 'disabled' |
|||
const CLASS_NAME_SHOW = 'show' |
|||
const CLASS_NAME_DROPUP = 'dropup' |
|||
const CLASS_NAME_DROPRIGHT = 'dropright' |
|||
const CLASS_NAME_DROPLEFT = 'dropleft' |
|||
const CLASS_NAME_MENURIGHT = 'dropdown-menu-right' |
|||
const CLASS_NAME_POSITION_STATIC = 'position-static' |
|||
|
|||
const SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]' |
|||
const SELECTOR_FORM_CHILD = '.dropdown form' |
|||
const SELECTOR_MENU = '.dropdown-menu' |
|||
const SELECTOR_NAVBAR_NAV = '.navbar-nav' |
|||
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' |
|||
|
|||
const PLACEMENT_TOP = 'top-start' |
|||
const PLACEMENT_TOPEND = 'top-end' |
|||
const PLACEMENT_BOTTOM = 'bottom-start' |
|||
const PLACEMENT_BOTTOMEND = 'bottom-end' |
|||
const PLACEMENT_RIGHT = 'right-start' |
|||
const PLACEMENT_LEFT = 'left-start' |
|||
|
|||
const Default = { |
|||
offset: 0, |
|||
flip: true, |
|||
boundary: 'scrollParent', |
|||
reference: 'toggle', |
|||
display: 'dynamic', |
|||
popperConfig: null |
|||
} |
|||
|
|||
const DefaultType = { |
|||
offset: '(number|string|function)', |
|||
flip: 'boolean', |
|||
boundary: '(string|element)', |
|||
reference: '(string|element)', |
|||
display: 'string', |
|||
popperConfig: '(null|object)' |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Dropdown { |
|||
constructor(element, config) { |
|||
this._element = element |
|||
this._popper = null |
|||
this._config = this._getConfig(config) |
|||
this._menu = this._getMenuElement() |
|||
this._inNavbar = this._detectNavbar() |
|||
|
|||
this._addEventListeners() |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
static get DefaultType() { |
|||
return DefaultType |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
toggle() { |
|||
if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED)) { |
|||
return |
|||
} |
|||
|
|||
const isActive = $(this._menu).hasClass(CLASS_NAME_SHOW) |
|||
|
|||
Dropdown._clearMenus() |
|||
|
|||
if (isActive) { |
|||
return |
|||
} |
|||
|
|||
this.show(true) |
|||
} |
|||
|
|||
show(usePopper = false) { |
|||
if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || $(this._menu).hasClass(CLASS_NAME_SHOW)) { |
|||
return |
|||
} |
|||
|
|||
const relatedTarget = { |
|||
relatedTarget: this._element |
|||
} |
|||
const showEvent = $.Event(EVENT_SHOW, relatedTarget) |
|||
const parent = Dropdown._getParentFromElement(this._element) |
|||
|
|||
$(parent).trigger(showEvent) |
|||
|
|||
if (showEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
// Totally disable Popper for Dropdowns in Navbar
|
|||
if (!this._inNavbar && usePopper) { |
|||
/** |
|||
* Check for Popper dependency |
|||
* Popper - https://popper.js.org
|
|||
*/ |
|||
if (typeof Popper === 'undefined') { |
|||
throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)') |
|||
} |
|||
|
|||
let referenceElement = this._element |
|||
|
|||
if (this._config.reference === 'parent') { |
|||
referenceElement = parent |
|||
} else if (Util.isElement(this._config.reference)) { |
|||
referenceElement = this._config.reference |
|||
|
|||
// Check if it's jQuery element
|
|||
if (typeof this._config.reference.jquery !== 'undefined') { |
|||
referenceElement = this._config.reference[0] |
|||
} |
|||
} |
|||
|
|||
// If boundary is not `scrollParent`, then set position to `static`
|
|||
// to allow the menu to "escape" the scroll parent's boundaries
|
|||
// https://github.com/twbs/bootstrap/issues/24251
|
|||
if (this._config.boundary !== 'scrollParent') { |
|||
$(parent).addClass(CLASS_NAME_POSITION_STATIC) |
|||
} |
|||
|
|||
this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()) |
|||
} |
|||
|
|||
// If this is a touch-enabled device we add extra
|
|||
// empty mouseover listeners to the body's immediate children;
|
|||
// only needed because of broken event delegation on iOS
|
|||
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
|||
if ('ontouchstart' in document.documentElement && |
|||
$(parent).closest(SELECTOR_NAVBAR_NAV).length === 0) { |
|||
$(document.body).children().on('mouseover', null, $.noop) |
|||
} |
|||
|
|||
this._element.focus() |
|||
this._element.setAttribute('aria-expanded', true) |
|||
|
|||
$(this._menu).toggleClass(CLASS_NAME_SHOW) |
|||
$(parent) |
|||
.toggleClass(CLASS_NAME_SHOW) |
|||
.trigger($.Event(EVENT_SHOWN, relatedTarget)) |
|||
} |
|||
|
|||
hide() { |
|||
if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || !$(this._menu).hasClass(CLASS_NAME_SHOW)) { |
|||
return |
|||
} |
|||
|
|||
const relatedTarget = { |
|||
relatedTarget: this._element |
|||
} |
|||
const hideEvent = $.Event(EVENT_HIDE, relatedTarget) |
|||
const parent = Dropdown._getParentFromElement(this._element) |
|||
|
|||
$(parent).trigger(hideEvent) |
|||
|
|||
if (hideEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
if (this._popper) { |
|||
this._popper.destroy() |
|||
} |
|||
|
|||
$(this._menu).toggleClass(CLASS_NAME_SHOW) |
|||
$(parent) |
|||
.toggleClass(CLASS_NAME_SHOW) |
|||
.trigger($.Event(EVENT_HIDDEN, relatedTarget)) |
|||
} |
|||
|
|||
dispose() { |
|||
$.removeData(this._element, DATA_KEY) |
|||
$(this._element).off(EVENT_KEY) |
|||
this._element = null |
|||
this._menu = null |
|||
if (this._popper !== null) { |
|||
this._popper.destroy() |
|||
this._popper = null |
|||
} |
|||
} |
|||
|
|||
update() { |
|||
this._inNavbar = this._detectNavbar() |
|||
if (this._popper !== null) { |
|||
this._popper.scheduleUpdate() |
|||
} |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_addEventListeners() { |
|||
$(this._element).on(EVENT_CLICK, event => { |
|||
event.preventDefault() |
|||
event.stopPropagation() |
|||
this.toggle() |
|||
}) |
|||
} |
|||
|
|||
_getConfig(config) { |
|||
config = { |
|||
...this.constructor.Default, |
|||
...$(this._element).data(), |
|||
...config |
|||
} |
|||
|
|||
Util.typeCheckConfig( |
|||
NAME, |
|||
config, |
|||
this.constructor.DefaultType |
|||
) |
|||
|
|||
return config |
|||
} |
|||
|
|||
_getMenuElement() { |
|||
if (!this._menu) { |
|||
const parent = Dropdown._getParentFromElement(this._element) |
|||
|
|||
if (parent) { |
|||
this._menu = parent.querySelector(SELECTOR_MENU) |
|||
} |
|||
} |
|||
|
|||
return this._menu |
|||
} |
|||
|
|||
_getPlacement() { |
|||
const $parentDropdown = $(this._element.parentNode) |
|||
let placement = PLACEMENT_BOTTOM |
|||
|
|||
// Handle dropup
|
|||
if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) { |
|||
placement = $(this._menu).hasClass(CLASS_NAME_MENURIGHT) ? |
|||
PLACEMENT_TOPEND : |
|||
PLACEMENT_TOP |
|||
} else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) { |
|||
placement = PLACEMENT_RIGHT |
|||
} else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) { |
|||
placement = PLACEMENT_LEFT |
|||
} else if ($(this._menu).hasClass(CLASS_NAME_MENURIGHT)) { |
|||
placement = PLACEMENT_BOTTOMEND |
|||
} |
|||
|
|||
return placement |
|||
} |
|||
|
|||
_detectNavbar() { |
|||
return $(this._element).closest('.navbar').length > 0 |
|||
} |
|||
|
|||
_getOffset() { |
|||
const offset = {} |
|||
|
|||
if (typeof this._config.offset === 'function') { |
|||
offset.fn = data => { |
|||
data.offsets = { |
|||
...data.offsets, |
|||
...(this._config.offset(data.offsets, this._element) || {}) |
|||
} |
|||
|
|||
return data |
|||
} |
|||
} else { |
|||
offset.offset = this._config.offset |
|||
} |
|||
|
|||
return offset |
|||
} |
|||
|
|||
_getPopperConfig() { |
|||
const popperConfig = { |
|||
placement: this._getPlacement(), |
|||
modifiers: { |
|||
offset: this._getOffset(), |
|||
flip: { |
|||
enabled: this._config.flip |
|||
}, |
|||
preventOverflow: { |
|||
boundariesElement: this._config.boundary |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Disable Popper if we have a static display
|
|||
if (this._config.display === 'static') { |
|||
popperConfig.modifiers.applyStyle = { |
|||
enabled: false |
|||
} |
|||
} |
|||
|
|||
return { |
|||
...popperConfig, |
|||
...this._config.popperConfig |
|||
} |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
let data = $(this).data(DATA_KEY) |
|||
const _config = typeof config === 'object' ? config : null |
|||
|
|||
if (!data) { |
|||
data = new Dropdown(this, _config) |
|||
$(this).data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config]() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
static _clearMenus(event) { |
|||
if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || |
|||
event.type === 'keyup' && event.which !== TAB_KEYCODE)) { |
|||
return |
|||
} |
|||
|
|||
const toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE)) |
|||
|
|||
for (let i = 0, len = toggles.length; i < len; i++) { |
|||
const parent = Dropdown._getParentFromElement(toggles[i]) |
|||
const context = $(toggles[i]).data(DATA_KEY) |
|||
const relatedTarget = { |
|||
relatedTarget: toggles[i] |
|||
} |
|||
|
|||
if (event && event.type === 'click') { |
|||
relatedTarget.clickEvent = event |
|||
} |
|||
|
|||
if (!context) { |
|||
continue |
|||
} |
|||
|
|||
const dropdownMenu = context._menu |
|||
if (!$(parent).hasClass(CLASS_NAME_SHOW)) { |
|||
continue |
|||
} |
|||
|
|||
if (event && (event.type === 'click' && |
|||
/input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && |
|||
$.contains(parent, event.target)) { |
|||
continue |
|||
} |
|||
|
|||
const hideEvent = $.Event(EVENT_HIDE, relatedTarget) |
|||
$(parent).trigger(hideEvent) |
|||
if (hideEvent.isDefaultPrevented()) { |
|||
continue |
|||
} |
|||
|
|||
// If this is a touch-enabled device we remove the extra
|
|||
// empty mouseover listeners we added for iOS support
|
|||
if ('ontouchstart' in document.documentElement) { |
|||
$(document.body).children().off('mouseover', null, $.noop) |
|||
} |
|||
|
|||
toggles[i].setAttribute('aria-expanded', 'false') |
|||
|
|||
if (context._popper) { |
|||
context._popper.destroy() |
|||
} |
|||
|
|||
$(dropdownMenu).removeClass(CLASS_NAME_SHOW) |
|||
$(parent) |
|||
.removeClass(CLASS_NAME_SHOW) |
|||
.trigger($.Event(EVENT_HIDDEN, relatedTarget)) |
|||
} |
|||
} |
|||
|
|||
static _getParentFromElement(element) { |
|||
let parent |
|||
const selector = Util.getSelectorFromElement(element) |
|||
|
|||
if (selector) { |
|||
parent = document.querySelector(selector) |
|||
} |
|||
|
|||
return parent || element.parentNode |
|||
} |
|||
|
|||
// eslint-disable-next-line complexity
|
|||
static _dataApiKeydownHandler(event) { |
|||
// If not input/textarea:
|
|||
// - And not a key in REGEXP_KEYDOWN => not a dropdown command
|
|||
// If input/textarea:
|
|||
// - If space key => not a dropdown command
|
|||
// - If key is other than escape
|
|||
// - If key is not up or down => not a dropdown command
|
|||
// - If trigger inside the menu => not a dropdown command
|
|||
if (/input|textarea/i.test(event.target.tagName) ? |
|||
event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && |
|||
(event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || |
|||
$(event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { |
|||
return |
|||
} |
|||
|
|||
if (this.disabled || $(this).hasClass(CLASS_NAME_DISABLED)) { |
|||
return |
|||
} |
|||
|
|||
const parent = Dropdown._getParentFromElement(this) |
|||
const isActive = $(parent).hasClass(CLASS_NAME_SHOW) |
|||
|
|||
if (!isActive && event.which === ESCAPE_KEYCODE) { |
|||
return |
|||
} |
|||
|
|||
event.preventDefault() |
|||
event.stopPropagation() |
|||
|
|||
if (!isActive || (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { |
|||
if (event.which === ESCAPE_KEYCODE) { |
|||
$(parent.querySelector(SELECTOR_DATA_TOGGLE)).trigger('focus') |
|||
} |
|||
|
|||
$(this).trigger('click') |
|||
return |
|||
} |
|||
|
|||
const items = [].slice.call(parent.querySelectorAll(SELECTOR_VISIBLE_ITEMS)) |
|||
.filter(item => $(item).is(':visible')) |
|||
|
|||
if (items.length === 0) { |
|||
return |
|||
} |
|||
|
|||
let index = items.indexOf(event.target) |
|||
|
|||
if (event.which === ARROW_UP_KEYCODE && index > 0) { // Up
|
|||
index-- |
|||
} |
|||
|
|||
if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { // Down
|
|||
index++ |
|||
} |
|||
|
|||
if (index < 0) { |
|||
index = 0 |
|||
} |
|||
|
|||
items[index].focus() |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(document) |
|||
.on(EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown._dataApiKeydownHandler) |
|||
.on(EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown._dataApiKeydownHandler) |
|||
.on(`${EVENT_CLICK_DATA_API} ${EVENT_KEYUP_DATA_API}`, Dropdown._clearMenus) |
|||
.on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { |
|||
event.preventDefault() |
|||
event.stopPropagation() |
|||
Dropdown._jQueryInterface.call($(this), 'toggle') |
|||
}) |
|||
.on(EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => { |
|||
e.stopPropagation() |
|||
}) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Dropdown._jQueryInterface |
|||
$.fn[NAME].Constructor = Dropdown |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Dropdown._jQueryInterface |
|||
} |
|||
|
|||
export default Dropdown |
@ -0,0 +1,629 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): modal.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'modal' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.modal' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
|
|||
|
|||
const Default = { |
|||
backdrop: true, |
|||
keyboard: true, |
|||
focus: true, |
|||
show: true |
|||
} |
|||
|
|||
const DefaultType = { |
|||
backdrop: '(boolean|string)', |
|||
keyboard: 'boolean', |
|||
focus: 'boolean', |
|||
show: 'boolean' |
|||
} |
|||
|
|||
const EVENT_HIDE = `hide${EVENT_KEY}` |
|||
const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}` |
|||
const EVENT_HIDDEN = `hidden${EVENT_KEY}` |
|||
const EVENT_SHOW = `show${EVENT_KEY}` |
|||
const EVENT_SHOWN = `shown${EVENT_KEY}` |
|||
const EVENT_FOCUSIN = `focusin${EVENT_KEY}` |
|||
const EVENT_RESIZE = `resize${EVENT_KEY}` |
|||
const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}` |
|||
const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}` |
|||
const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}` |
|||
const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}` |
|||
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
const CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable' |
|||
const CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure' |
|||
const CLASS_NAME_BACKDROP = 'modal-backdrop' |
|||
const CLASS_NAME_OPEN = 'modal-open' |
|||
const CLASS_NAME_FADE = 'fade' |
|||
const CLASS_NAME_SHOW = 'show' |
|||
const CLASS_NAME_STATIC = 'modal-static' |
|||
|
|||
const SELECTOR_DIALOG = '.modal-dialog' |
|||
const SELECTOR_MODAL_BODY = '.modal-body' |
|||
const SELECTOR_DATA_TOGGLE = '[data-toggle="modal"]' |
|||
const SELECTOR_DATA_DISMISS = '[data-dismiss="modal"]' |
|||
const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top' |
|||
const SELECTOR_STICKY_CONTENT = '.sticky-top' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Modal { |
|||
constructor(element, config) { |
|||
this._config = this._getConfig(config) |
|||
this._element = element |
|||
this._dialog = element.querySelector(SELECTOR_DIALOG) |
|||
this._backdrop = null |
|||
this._isShown = false |
|||
this._isBodyOverflowing = false |
|||
this._ignoreBackdropClick = false |
|||
this._isTransitioning = false |
|||
this._scrollbarWidth = 0 |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
toggle(relatedTarget) { |
|||
return this._isShown ? this.hide() : this.show(relatedTarget) |
|||
} |
|||
|
|||
show(relatedTarget) { |
|||
if (this._isShown || this._isTransitioning) { |
|||
return |
|||
} |
|||
|
|||
if ($(this._element).hasClass(CLASS_NAME_FADE)) { |
|||
this._isTransitioning = true |
|||
} |
|||
|
|||
const showEvent = $.Event(EVENT_SHOW, { |
|||
relatedTarget |
|||
}) |
|||
|
|||
$(this._element).trigger(showEvent) |
|||
|
|||
if (this._isShown || showEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
this._isShown = true |
|||
|
|||
this._checkScrollbar() |
|||
this._setScrollbar() |
|||
|
|||
this._adjustDialog() |
|||
|
|||
this._setEscapeEvent() |
|||
this._setResizeEvent() |
|||
|
|||
$(this._element).on( |
|||
EVENT_CLICK_DISMISS, |
|||
SELECTOR_DATA_DISMISS, |
|||
event => this.hide(event) |
|||
) |
|||
|
|||
$(this._dialog).on(EVENT_MOUSEDOWN_DISMISS, () => { |
|||
$(this._element).one(EVENT_MOUSEUP_DISMISS, event => { |
|||
if ($(event.target).is(this._element)) { |
|||
this._ignoreBackdropClick = true |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
this._showBackdrop(() => this._showElement(relatedTarget)) |
|||
} |
|||
|
|||
hide(event) { |
|||
if (event) { |
|||
event.preventDefault() |
|||
} |
|||
|
|||
if (!this._isShown || this._isTransitioning) { |
|||
return |
|||
} |
|||
|
|||
const hideEvent = $.Event(EVENT_HIDE) |
|||
|
|||
$(this._element).trigger(hideEvent) |
|||
|
|||
if (!this._isShown || hideEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
this._isShown = false |
|||
const transition = $(this._element).hasClass(CLASS_NAME_FADE) |
|||
|
|||
if (transition) { |
|||
this._isTransitioning = true |
|||
} |
|||
|
|||
this._setEscapeEvent() |
|||
this._setResizeEvent() |
|||
|
|||
$(document).off(EVENT_FOCUSIN) |
|||
|
|||
$(this._element).removeClass(CLASS_NAME_SHOW) |
|||
|
|||
$(this._element).off(EVENT_CLICK_DISMISS) |
|||
$(this._dialog).off(EVENT_MOUSEDOWN_DISMISS) |
|||
|
|||
if (transition) { |
|||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) |
|||
|
|||
$(this._element) |
|||
.one(Util.TRANSITION_END, event => this._hideModal(event)) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
this._hideModal() |
|||
} |
|||
} |
|||
|
|||
dispose() { |
|||
[window, this._element, this._dialog] |
|||
.forEach(htmlElement => $(htmlElement).off(EVENT_KEY)) |
|||
|
|||
/** |
|||
* `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API` |
|||
* Do not move `document` in `htmlElements` array |
|||
* It will remove `EVENT_CLICK_DATA_API` event that should remain |
|||
*/ |
|||
$(document).off(EVENT_FOCUSIN) |
|||
|
|||
$.removeData(this._element, DATA_KEY) |
|||
|
|||
this._config = null |
|||
this._element = null |
|||
this._dialog = null |
|||
this._backdrop = null |
|||
this._isShown = null |
|||
this._isBodyOverflowing = null |
|||
this._ignoreBackdropClick = null |
|||
this._isTransitioning = null |
|||
this._scrollbarWidth = null |
|||
} |
|||
|
|||
handleUpdate() { |
|||
this._adjustDialog() |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getConfig(config) { |
|||
config = { |
|||
...Default, |
|||
...config |
|||
} |
|||
Util.typeCheckConfig(NAME, config, DefaultType) |
|||
return config |
|||
} |
|||
|
|||
_triggerBackdropTransition() { |
|||
const hideEventPrevented = $.Event(EVENT_HIDE_PREVENTED) |
|||
|
|||
$(this._element).trigger(hideEventPrevented) |
|||
if (hideEventPrevented.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight |
|||
|
|||
if (!isModalOverflowing) { |
|||
this._element.style.overflowY = 'hidden' |
|||
} |
|||
|
|||
this._element.classList.add(CLASS_NAME_STATIC) |
|||
|
|||
const modalTransitionDuration = Util.getTransitionDurationFromElement(this._dialog) |
|||
$(this._element).off(Util.TRANSITION_END) |
|||
|
|||
$(this._element).one(Util.TRANSITION_END, () => { |
|||
this._element.classList.remove(CLASS_NAME_STATIC) |
|||
if (!isModalOverflowing) { |
|||
$(this._element).one(Util.TRANSITION_END, () => { |
|||
this._element.style.overflowY = '' |
|||
}) |
|||
.emulateTransitionEnd(this._element, modalTransitionDuration) |
|||
} |
|||
}) |
|||
.emulateTransitionEnd(modalTransitionDuration) |
|||
this._element.focus() |
|||
} |
|||
|
|||
_showElement(relatedTarget) { |
|||
const transition = $(this._element).hasClass(CLASS_NAME_FADE) |
|||
const modalBody = this._dialog ? this._dialog.querySelector(SELECTOR_MODAL_BODY) : null |
|||
|
|||
if (!this._element.parentNode || |
|||
this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { |
|||
// Don't move modal's DOM position
|
|||
document.body.appendChild(this._element) |
|||
} |
|||
|
|||
this._element.style.display = 'block' |
|||
this._element.removeAttribute('aria-hidden') |
|||
this._element.setAttribute('aria-modal', true) |
|||
this._element.setAttribute('role', 'dialog') |
|||
|
|||
if ($(this._dialog).hasClass(CLASS_NAME_SCROLLABLE) && modalBody) { |
|||
modalBody.scrollTop = 0 |
|||
} else { |
|||
this._element.scrollTop = 0 |
|||
} |
|||
|
|||
if (transition) { |
|||
Util.reflow(this._element) |
|||
} |
|||
|
|||
$(this._element).addClass(CLASS_NAME_SHOW) |
|||
|
|||
if (this._config.focus) { |
|||
this._enforceFocus() |
|||
} |
|||
|
|||
const shownEvent = $.Event(EVENT_SHOWN, { |
|||
relatedTarget |
|||
}) |
|||
|
|||
const transitionComplete = () => { |
|||
if (this._config.focus) { |
|||
this._element.focus() |
|||
} |
|||
|
|||
this._isTransitioning = false |
|||
$(this._element).trigger(shownEvent) |
|||
} |
|||
|
|||
if (transition) { |
|||
const transitionDuration = Util.getTransitionDurationFromElement(this._dialog) |
|||
|
|||
$(this._dialog) |
|||
.one(Util.TRANSITION_END, transitionComplete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
transitionComplete() |
|||
} |
|||
} |
|||
|
|||
_enforceFocus() { |
|||
$(document) |
|||
.off(EVENT_FOCUSIN) // Guard against infinite focus loop
|
|||
.on(EVENT_FOCUSIN, event => { |
|||
if (document !== event.target && |
|||
this._element !== event.target && |
|||
$(this._element).has(event.target).length === 0) { |
|||
this._element.focus() |
|||
} |
|||
}) |
|||
} |
|||
|
|||
_setEscapeEvent() { |
|||
if (this._isShown) { |
|||
$(this._element).on(EVENT_KEYDOWN_DISMISS, event => { |
|||
if (this._config.keyboard && event.which === ESCAPE_KEYCODE) { |
|||
event.preventDefault() |
|||
this.hide() |
|||
} else if (!this._config.keyboard && event.which === ESCAPE_KEYCODE) { |
|||
this._triggerBackdropTransition() |
|||
} |
|||
}) |
|||
} else if (!this._isShown) { |
|||
$(this._element).off(EVENT_KEYDOWN_DISMISS) |
|||
} |
|||
} |
|||
|
|||
_setResizeEvent() { |
|||
if (this._isShown) { |
|||
$(window).on(EVENT_RESIZE, event => this.handleUpdate(event)) |
|||
} else { |
|||
$(window).off(EVENT_RESIZE) |
|||
} |
|||
} |
|||
|
|||
_hideModal() { |
|||
this._element.style.display = 'none' |
|||
this._element.setAttribute('aria-hidden', true) |
|||
this._element.removeAttribute('aria-modal') |
|||
this._element.removeAttribute('role') |
|||
this._isTransitioning = false |
|||
this._showBackdrop(() => { |
|||
$(document.body).removeClass(CLASS_NAME_OPEN) |
|||
this._resetAdjustments() |
|||
this._resetScrollbar() |
|||
$(this._element).trigger(EVENT_HIDDEN) |
|||
}) |
|||
} |
|||
|
|||
_removeBackdrop() { |
|||
if (this._backdrop) { |
|||
$(this._backdrop).remove() |
|||
this._backdrop = null |
|||
} |
|||
} |
|||
|
|||
_showBackdrop(callback) { |
|||
const animate = $(this._element).hasClass(CLASS_NAME_FADE) ? |
|||
CLASS_NAME_FADE : '' |
|||
|
|||
if (this._isShown && this._config.backdrop) { |
|||
this._backdrop = document.createElement('div') |
|||
this._backdrop.className = CLASS_NAME_BACKDROP |
|||
|
|||
if (animate) { |
|||
this._backdrop.classList.add(animate) |
|||
} |
|||
|
|||
$(this._backdrop).appendTo(document.body) |
|||
|
|||
$(this._element).on(EVENT_CLICK_DISMISS, event => { |
|||
if (this._ignoreBackdropClick) { |
|||
this._ignoreBackdropClick = false |
|||
return |
|||
} |
|||
|
|||
if (event.target !== event.currentTarget) { |
|||
return |
|||
} |
|||
|
|||
if (this._config.backdrop === 'static') { |
|||
this._triggerBackdropTransition() |
|||
} else { |
|||
this.hide() |
|||
} |
|||
}) |
|||
|
|||
if (animate) { |
|||
Util.reflow(this._backdrop) |
|||
} |
|||
|
|||
$(this._backdrop).addClass(CLASS_NAME_SHOW) |
|||
|
|||
if (!callback) { |
|||
return |
|||
} |
|||
|
|||
if (!animate) { |
|||
callback() |
|||
return |
|||
} |
|||
|
|||
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) |
|||
|
|||
$(this._backdrop) |
|||
.one(Util.TRANSITION_END, callback) |
|||
.emulateTransitionEnd(backdropTransitionDuration) |
|||
} else if (!this._isShown && this._backdrop) { |
|||
$(this._backdrop).removeClass(CLASS_NAME_SHOW) |
|||
|
|||
const callbackRemove = () => { |
|||
this._removeBackdrop() |
|||
if (callback) { |
|||
callback() |
|||
} |
|||
} |
|||
|
|||
if ($(this._element).hasClass(CLASS_NAME_FADE)) { |
|||
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) |
|||
|
|||
$(this._backdrop) |
|||
.one(Util.TRANSITION_END, callbackRemove) |
|||
.emulateTransitionEnd(backdropTransitionDuration) |
|||
} else { |
|||
callbackRemove() |
|||
} |
|||
} else if (callback) { |
|||
callback() |
|||
} |
|||
} |
|||
|
|||
// ----------------------------------------------------------------------
|
|||
// the following methods are used to handle overflowing modals
|
|||
// todo (fat): these should probably be refactored out of modal.js
|
|||
// ----------------------------------------------------------------------
|
|||
|
|||
_adjustDialog() { |
|||
const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight |
|||
|
|||
if (!this._isBodyOverflowing && isModalOverflowing) { |
|||
this._element.style.paddingLeft = `${this._scrollbarWidth}px` |
|||
} |
|||
|
|||
if (this._isBodyOverflowing && !isModalOverflowing) { |
|||
this._element.style.paddingRight = `${this._scrollbarWidth}px` |
|||
} |
|||
} |
|||
|
|||
_resetAdjustments() { |
|||
this._element.style.paddingLeft = '' |
|||
this._element.style.paddingRight = '' |
|||
} |
|||
|
|||
_checkScrollbar() { |
|||
const rect = document.body.getBoundingClientRect() |
|||
this._isBodyOverflowing = Math.round(rect.left + rect.right) < window.innerWidth |
|||
this._scrollbarWidth = this._getScrollbarWidth() |
|||
} |
|||
|
|||
_setScrollbar() { |
|||
if (this._isBodyOverflowing) { |
|||
// Note: DOMNode.style.paddingRight returns the actual value or '' if not set
|
|||
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
|
|||
const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT)) |
|||
const stickyContent = [].slice.call(document.querySelectorAll(SELECTOR_STICKY_CONTENT)) |
|||
|
|||
// Adjust fixed content padding
|
|||
$(fixedContent).each((index, element) => { |
|||
const actualPadding = element.style.paddingRight |
|||
const calculatedPadding = $(element).css('padding-right') |
|||
$(element) |
|||
.data('padding-right', actualPadding) |
|||
.css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) |
|||
}) |
|||
|
|||
// Adjust sticky content margin
|
|||
$(stickyContent).each((index, element) => { |
|||
const actualMargin = element.style.marginRight |
|||
const calculatedMargin = $(element).css('margin-right') |
|||
$(element) |
|||
.data('margin-right', actualMargin) |
|||
.css('margin-right', `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`) |
|||
}) |
|||
|
|||
// Adjust body padding
|
|||
const actualPadding = document.body.style.paddingRight |
|||
const calculatedPadding = $(document.body).css('padding-right') |
|||
$(document.body) |
|||
.data('padding-right', actualPadding) |
|||
.css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) |
|||
} |
|||
|
|||
$(document.body).addClass(CLASS_NAME_OPEN) |
|||
} |
|||
|
|||
_resetScrollbar() { |
|||
// Restore fixed content padding
|
|||
const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT)) |
|||
$(fixedContent).each((index, element) => { |
|||
const padding = $(element).data('padding-right') |
|||
$(element).removeData('padding-right') |
|||
element.style.paddingRight = padding ? padding : '' |
|||
}) |
|||
|
|||
// Restore sticky content
|
|||
const elements = [].slice.call(document.querySelectorAll(`${SELECTOR_STICKY_CONTENT}`)) |
|||
$(elements).each((index, element) => { |
|||
const margin = $(element).data('margin-right') |
|||
if (typeof margin !== 'undefined') { |
|||
$(element).css('margin-right', margin).removeData('margin-right') |
|||
} |
|||
}) |
|||
|
|||
// Restore body padding
|
|||
const padding = $(document.body).data('padding-right') |
|||
$(document.body).removeData('padding-right') |
|||
document.body.style.paddingRight = padding ? padding : '' |
|||
} |
|||
|
|||
_getScrollbarWidth() { // thx d.walsh
|
|||
const scrollDiv = document.createElement('div') |
|||
scrollDiv.className = CLASS_NAME_SCROLLBAR_MEASURER |
|||
document.body.appendChild(scrollDiv) |
|||
const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth |
|||
document.body.removeChild(scrollDiv) |
|||
return scrollbarWidth |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config, relatedTarget) { |
|||
return this.each(function () { |
|||
let data = $(this).data(DATA_KEY) |
|||
const _config = { |
|||
...Default, |
|||
...$(this).data(), |
|||
...(typeof config === 'object' && config ? config : {}) |
|||
} |
|||
|
|||
if (!data) { |
|||
data = new Modal(this, _config) |
|||
$(this).data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config](relatedTarget) |
|||
} else if (_config.show) { |
|||
data.show(relatedTarget) |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { |
|||
let target |
|||
const selector = Util.getSelectorFromElement(this) |
|||
|
|||
if (selector) { |
|||
target = document.querySelector(selector) |
|||
} |
|||
|
|||
const config = $(target).data(DATA_KEY) ? |
|||
'toggle' : { |
|||
...$(target).data(), |
|||
...$(this).data() |
|||
} |
|||
|
|||
if (this.tagName === 'A' || this.tagName === 'AREA') { |
|||
event.preventDefault() |
|||
} |
|||
|
|||
const $target = $(target).one(EVENT_SHOW, showEvent => { |
|||
if (showEvent.isDefaultPrevented()) { |
|||
// Only register focus restorer if modal will actually get shown
|
|||
return |
|||
} |
|||
|
|||
$target.one(EVENT_HIDDEN, () => { |
|||
if ($(this).is(':visible')) { |
|||
this.focus() |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
Modal._jQueryInterface.call($(target), config, this) |
|||
}) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Modal._jQueryInterface |
|||
$.fn[NAME].Constructor = Modal |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Modal._jQueryInterface |
|||
} |
|||
|
|||
export default Modal |
@ -0,0 +1,182 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): popover.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Tooltip from './tooltip' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'popover' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.popover' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
const CLASS_PREFIX = 'bs-popover' |
|||
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') |
|||
|
|||
const Default = { |
|||
...Tooltip.Default, |
|||
placement: 'right', |
|||
trigger: 'click', |
|||
content: '', |
|||
template: '<div class="popover" role="tooltip">' + |
|||
'<div class="arrow"></div>' + |
|||
'<h3 class="popover-header"></h3>' + |
|||
'<div class="popover-body"></div></div>' |
|||
} |
|||
|
|||
const DefaultType = { |
|||
...Tooltip.DefaultType, |
|||
content: '(string|element|function)' |
|||
} |
|||
|
|||
const CLASS_NAME_FADE = 'fade' |
|||
const CLASS_NAME_SHOW = 'show' |
|||
|
|||
const SELECTOR_TITLE = '.popover-header' |
|||
const SELECTOR_CONTENT = '.popover-body' |
|||
|
|||
const Event = { |
|||
HIDE: `hide${EVENT_KEY}`, |
|||
HIDDEN: `hidden${EVENT_KEY}`, |
|||
SHOW: `show${EVENT_KEY}`, |
|||
SHOWN: `shown${EVENT_KEY}`, |
|||
INSERTED: `inserted${EVENT_KEY}`, |
|||
CLICK: `click${EVENT_KEY}`, |
|||
FOCUSIN: `focusin${EVENT_KEY}`, |
|||
FOCUSOUT: `focusout${EVENT_KEY}`, |
|||
MOUSEENTER: `mouseenter${EVENT_KEY}`, |
|||
MOUSELEAVE: `mouseleave${EVENT_KEY}` |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Popover extends Tooltip { |
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
static get NAME() { |
|||
return NAME |
|||
} |
|||
|
|||
static get DATA_KEY() { |
|||
return DATA_KEY |
|||
} |
|||
|
|||
static get Event() { |
|||
return Event |
|||
} |
|||
|
|||
static get EVENT_KEY() { |
|||
return EVENT_KEY |
|||
} |
|||
|
|||
static get DefaultType() { |
|||
return DefaultType |
|||
} |
|||
|
|||
// Overrides
|
|||
|
|||
isWithContent() { |
|||
return this.getTitle() || this._getContent() |
|||
} |
|||
|
|||
addAttachmentClass(attachment) { |
|||
$(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) |
|||
} |
|||
|
|||
getTipElement() { |
|||
this.tip = this.tip || $(this.config.template)[0] |
|||
return this.tip |
|||
} |
|||
|
|||
setContent() { |
|||
const $tip = $(this.getTipElement()) |
|||
|
|||
// We use append for html objects to maintain js events
|
|||
this.setElementContent($tip.find(SELECTOR_TITLE), this.getTitle()) |
|||
let content = this._getContent() |
|||
if (typeof content === 'function') { |
|||
content = content.call(this.element) |
|||
} |
|||
|
|||
this.setElementContent($tip.find(SELECTOR_CONTENT), content) |
|||
|
|||
$tip.removeClass(`${CLASS_NAME_FADE} ${CLASS_NAME_SHOW}`) |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getContent() { |
|||
return this.element.getAttribute('data-content') || |
|||
this.config.content |
|||
} |
|||
|
|||
_cleanTipClass() { |
|||
const $tip = $(this.getTipElement()) |
|||
const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) |
|||
if (tabClass !== null && tabClass.length > 0) { |
|||
$tip.removeClass(tabClass.join('')) |
|||
} |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
let data = $(this).data(DATA_KEY) |
|||
const _config = typeof config === 'object' ? config : null |
|||
|
|||
if (!data && /dispose|hide/.test(config)) { |
|||
return |
|||
} |
|||
|
|||
if (!data) { |
|||
data = new Popover(this, _config) |
|||
$(this).data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config]() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Popover._jQueryInterface |
|||
$.fn[NAME].Constructor = Popover |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Popover._jQueryInterface |
|||
} |
|||
|
|||
export default Popover |
@ -0,0 +1,324 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): scrollspy.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'scrollspy' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.scrollspy' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
|
|||
const Default = { |
|||
offset: 10, |
|||
method: 'auto', |
|||
target: '' |
|||
} |
|||
|
|||
const DefaultType = { |
|||
offset: 'number', |
|||
method: 'string', |
|||
target: '(string|element)' |
|||
} |
|||
|
|||
const EVENT_ACTIVATE = `activate${EVENT_KEY}` |
|||
const EVENT_SCROLL = `scroll${EVENT_KEY}` |
|||
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item' |
|||
const CLASS_NAME_ACTIVE = 'active' |
|||
|
|||
const SELECTOR_DATA_SPY = '[data-spy="scroll"]' |
|||
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group' |
|||
const SELECTOR_NAV_LINKS = '.nav-link' |
|||
const SELECTOR_NAV_ITEMS = '.nav-item' |
|||
const SELECTOR_LIST_ITEMS = '.list-group-item' |
|||
const SELECTOR_DROPDOWN = '.dropdown' |
|||
const SELECTOR_DROPDOWN_ITEMS = '.dropdown-item' |
|||
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle' |
|||
|
|||
const METHOD_OFFSET = 'offset' |
|||
const METHOD_POSITION = 'position' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class ScrollSpy { |
|||
constructor(element, config) { |
|||
this._element = element |
|||
this._scrollElement = element.tagName === 'BODY' ? window : element |
|||
this._config = this._getConfig(config) |
|||
this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS},` + |
|||
`${this._config.target} ${SELECTOR_LIST_ITEMS},` + |
|||
`${this._config.target} ${SELECTOR_DROPDOWN_ITEMS}` |
|||
this._offsets = [] |
|||
this._targets = [] |
|||
this._activeTarget = null |
|||
this._scrollHeight = 0 |
|||
|
|||
$(this._scrollElement).on(EVENT_SCROLL, event => this._process(event)) |
|||
|
|||
this.refresh() |
|||
this._process() |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
refresh() { |
|||
const autoMethod = this._scrollElement === this._scrollElement.window ? |
|||
METHOD_OFFSET : METHOD_POSITION |
|||
|
|||
const offsetMethod = this._config.method === 'auto' ? |
|||
autoMethod : this._config.method |
|||
|
|||
const offsetBase = offsetMethod === METHOD_POSITION ? |
|||
this._getScrollTop() : 0 |
|||
|
|||
this._offsets = [] |
|||
this._targets = [] |
|||
|
|||
this._scrollHeight = this._getScrollHeight() |
|||
|
|||
const targets = [].slice.call(document.querySelectorAll(this._selector)) |
|||
|
|||
targets |
|||
.map(element => { |
|||
let target |
|||
const targetSelector = Util.getSelectorFromElement(element) |
|||
|
|||
if (targetSelector) { |
|||
target = document.querySelector(targetSelector) |
|||
} |
|||
|
|||
if (target) { |
|||
const targetBCR = target.getBoundingClientRect() |
|||
if (targetBCR.width || targetBCR.height) { |
|||
// TODO (fat): remove sketch reliance on jQuery position/offset
|
|||
return [ |
|||
$(target)[offsetMethod]().top + offsetBase, |
|||
targetSelector |
|||
] |
|||
} |
|||
} |
|||
|
|||
return null |
|||
}) |
|||
.filter(item => item) |
|||
.sort((a, b) => a[0] - b[0]) |
|||
.forEach(item => { |
|||
this._offsets.push(item[0]) |
|||
this._targets.push(item[1]) |
|||
}) |
|||
} |
|||
|
|||
dispose() { |
|||
$.removeData(this._element, DATA_KEY) |
|||
$(this._scrollElement).off(EVENT_KEY) |
|||
|
|||
this._element = null |
|||
this._scrollElement = null |
|||
this._config = null |
|||
this._selector = null |
|||
this._offsets = null |
|||
this._targets = null |
|||
this._activeTarget = null |
|||
this._scrollHeight = null |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getConfig(config) { |
|||
config = { |
|||
...Default, |
|||
...(typeof config === 'object' && config ? config : {}) |
|||
} |
|||
|
|||
if (typeof config.target !== 'string' && Util.isElement(config.target)) { |
|||
let id = $(config.target).attr('id') |
|||
if (!id) { |
|||
id = Util.getUID(NAME) |
|||
$(config.target).attr('id', id) |
|||
} |
|||
|
|||
config.target = `#${id}` |
|||
} |
|||
|
|||
Util.typeCheckConfig(NAME, config, DefaultType) |
|||
|
|||
return config |
|||
} |
|||
|
|||
_getScrollTop() { |
|||
return this._scrollElement === window ? |
|||
this._scrollElement.pageYOffset : this._scrollElement.scrollTop |
|||
} |
|||
|
|||
_getScrollHeight() { |
|||
return this._scrollElement.scrollHeight || Math.max( |
|||
document.body.scrollHeight, |
|||
document.documentElement.scrollHeight |
|||
) |
|||
} |
|||
|
|||
_getOffsetHeight() { |
|||
return this._scrollElement === window ? |
|||
window.innerHeight : this._scrollElement.getBoundingClientRect().height |
|||
} |
|||
|
|||
_process() { |
|||
const scrollTop = this._getScrollTop() + this._config.offset |
|||
const scrollHeight = this._getScrollHeight() |
|||
const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight() |
|||
|
|||
if (this._scrollHeight !== scrollHeight) { |
|||
this.refresh() |
|||
} |
|||
|
|||
if (scrollTop >= maxScroll) { |
|||
const target = this._targets[this._targets.length - 1] |
|||
|
|||
if (this._activeTarget !== target) { |
|||
this._activate(target) |
|||
} |
|||
|
|||
return |
|||
} |
|||
|
|||
if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { |
|||
this._activeTarget = null |
|||
this._clear() |
|||
return |
|||
} |
|||
|
|||
for (let i = this._offsets.length; i--;) { |
|||
const isActiveTarget = this._activeTarget !== this._targets[i] && |
|||
scrollTop >= this._offsets[i] && |
|||
(typeof this._offsets[i + 1] === 'undefined' || |
|||
scrollTop < this._offsets[i + 1]) |
|||
|
|||
if (isActiveTarget) { |
|||
this._activate(this._targets[i]) |
|||
} |
|||
} |
|||
} |
|||
|
|||
_activate(target) { |
|||
this._activeTarget = target |
|||
|
|||
this._clear() |
|||
|
|||
const queries = this._selector |
|||
.split(',') |
|||
.map(selector => `${selector}[data-target="${target}"],${selector}[href="${target}"]`) |
|||
|
|||
const $link = $([].slice.call(document.querySelectorAll(queries.join(',')))) |
|||
|
|||
if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) { |
|||
$link.closest(SELECTOR_DROPDOWN) |
|||
.find(SELECTOR_DROPDOWN_TOGGLE) |
|||
.addClass(CLASS_NAME_ACTIVE) |
|||
$link.addClass(CLASS_NAME_ACTIVE) |
|||
} else { |
|||
// Set triggered link as active
|
|||
$link.addClass(CLASS_NAME_ACTIVE) |
|||
// Set triggered links parents as active
|
|||
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
|
|||
$link.parents(SELECTOR_NAV_LIST_GROUP) |
|||
.prev(`${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`) |
|||
.addClass(CLASS_NAME_ACTIVE) |
|||
// Handle special case when .nav-link is inside .nav-item
|
|||
$link.parents(SELECTOR_NAV_LIST_GROUP) |
|||
.prev(SELECTOR_NAV_ITEMS) |
|||
.children(SELECTOR_NAV_LINKS) |
|||
.addClass(CLASS_NAME_ACTIVE) |
|||
} |
|||
|
|||
$(this._scrollElement).trigger(EVENT_ACTIVATE, { |
|||
relatedTarget: target |
|||
}) |
|||
} |
|||
|
|||
_clear() { |
|||
[].slice.call(document.querySelectorAll(this._selector)) |
|||
.filter(node => node.classList.contains(CLASS_NAME_ACTIVE)) |
|||
.forEach(node => node.classList.remove(CLASS_NAME_ACTIVE)) |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
let data = $(this).data(DATA_KEY) |
|||
const _config = typeof config === 'object' && config |
|||
|
|||
if (!data) { |
|||
data = new ScrollSpy(this, _config) |
|||
$(this).data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config]() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(window).on(EVENT_LOAD_DATA_API, () => { |
|||
const scrollSpys = [].slice.call(document.querySelectorAll(SELECTOR_DATA_SPY)) |
|||
const scrollSpysLength = scrollSpys.length |
|||
|
|||
for (let i = scrollSpysLength; i--;) { |
|||
const $spy = $(scrollSpys[i]) |
|||
ScrollSpy._jQueryInterface.call($spy, $spy.data()) |
|||
} |
|||
}) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = ScrollSpy._jQueryInterface |
|||
$.fn[NAME].Constructor = ScrollSpy |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return ScrollSpy._jQueryInterface |
|||
} |
|||
|
|||
export default ScrollSpy |
@ -0,0 +1,255 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): tab.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'tab' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.tab' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const DATA_API_KEY = '.data-api' |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
|
|||
const EVENT_HIDE = `hide${EVENT_KEY}` |
|||
const EVENT_HIDDEN = `hidden${EVENT_KEY}` |
|||
const EVENT_SHOW = `show${EVENT_KEY}` |
|||
const EVENT_SHOWN = `shown${EVENT_KEY}` |
|||
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` |
|||
|
|||
const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu' |
|||
const CLASS_NAME_ACTIVE = 'active' |
|||
const CLASS_NAME_DISABLED = 'disabled' |
|||
const CLASS_NAME_FADE = 'fade' |
|||
const CLASS_NAME_SHOW = 'show' |
|||
|
|||
const SELECTOR_DROPDOWN = '.dropdown' |
|||
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group' |
|||
const SELECTOR_ACTIVE = '.active' |
|||
const SELECTOR_ACTIVE_UL = '> li > .active' |
|||
const SELECTOR_DATA_TOGGLE = '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]' |
|||
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle' |
|||
const SELECTOR_DROPDOWN_ACTIVE_CHILD = '> .dropdown-menu .active' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Tab { |
|||
constructor(element) { |
|||
this._element = element |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
show() { |
|||
if (this._element.parentNode && |
|||
this._element.parentNode.nodeType === Node.ELEMENT_NODE && |
|||
$(this._element).hasClass(CLASS_NAME_ACTIVE) || |
|||
$(this._element).hasClass(CLASS_NAME_DISABLED)) { |
|||
return |
|||
} |
|||
|
|||
let target |
|||
let previous |
|||
const listElement = $(this._element).closest(SELECTOR_NAV_LIST_GROUP)[0] |
|||
const selector = Util.getSelectorFromElement(this._element) |
|||
|
|||
if (listElement) { |
|||
const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE |
|||
previous = $.makeArray($(listElement).find(itemSelector)) |
|||
previous = previous[previous.length - 1] |
|||
} |
|||
|
|||
const hideEvent = $.Event(EVENT_HIDE, { |
|||
relatedTarget: this._element |
|||
}) |
|||
|
|||
const showEvent = $.Event(EVENT_SHOW, { |
|||
relatedTarget: previous |
|||
}) |
|||
|
|||
if (previous) { |
|||
$(previous).trigger(hideEvent) |
|||
} |
|||
|
|||
$(this._element).trigger(showEvent) |
|||
|
|||
if (showEvent.isDefaultPrevented() || |
|||
hideEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
if (selector) { |
|||
target = document.querySelector(selector) |
|||
} |
|||
|
|||
this._activate( |
|||
this._element, |
|||
listElement |
|||
) |
|||
|
|||
const complete = () => { |
|||
const hiddenEvent = $.Event(EVENT_HIDDEN, { |
|||
relatedTarget: this._element |
|||
}) |
|||
|
|||
const shownEvent = $.Event(EVENT_SHOWN, { |
|||
relatedTarget: previous |
|||
}) |
|||
|
|||
$(previous).trigger(hiddenEvent) |
|||
$(this._element).trigger(shownEvent) |
|||
} |
|||
|
|||
if (target) { |
|||
this._activate(target, target.parentNode, complete) |
|||
} else { |
|||
complete() |
|||
} |
|||
} |
|||
|
|||
dispose() { |
|||
$.removeData(this._element, DATA_KEY) |
|||
this._element = null |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_activate(element, container, callback) { |
|||
const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? |
|||
$(container).find(SELECTOR_ACTIVE_UL) : |
|||
$(container).children(SELECTOR_ACTIVE) |
|||
|
|||
const active = activeElements[0] |
|||
const isTransitioning = callback && (active && $(active).hasClass(CLASS_NAME_FADE)) |
|||
const complete = () => this._transitionComplete( |
|||
element, |
|||
active, |
|||
callback |
|||
) |
|||
|
|||
if (active && isTransitioning) { |
|||
const transitionDuration = Util.getTransitionDurationFromElement(active) |
|||
|
|||
$(active) |
|||
.removeClass(CLASS_NAME_SHOW) |
|||
.one(Util.TRANSITION_END, complete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
complete() |
|||
} |
|||
} |
|||
|
|||
_transitionComplete(element, active, callback) { |
|||
if (active) { |
|||
$(active).removeClass(CLASS_NAME_ACTIVE) |
|||
|
|||
const dropdownChild = $(active.parentNode).find( |
|||
SELECTOR_DROPDOWN_ACTIVE_CHILD |
|||
)[0] |
|||
|
|||
if (dropdownChild) { |
|||
$(dropdownChild).removeClass(CLASS_NAME_ACTIVE) |
|||
} |
|||
|
|||
if (active.getAttribute('role') === 'tab') { |
|||
active.setAttribute('aria-selected', false) |
|||
} |
|||
} |
|||
|
|||
$(element).addClass(CLASS_NAME_ACTIVE) |
|||
if (element.getAttribute('role') === 'tab') { |
|||
element.setAttribute('aria-selected', true) |
|||
} |
|||
|
|||
Util.reflow(element) |
|||
|
|||
if (element.classList.contains(CLASS_NAME_FADE)) { |
|||
element.classList.add(CLASS_NAME_SHOW) |
|||
} |
|||
|
|||
if (element.parentNode && $(element.parentNode).hasClass(CLASS_NAME_DROPDOWN_MENU)) { |
|||
const dropdownElement = $(element).closest(SELECTOR_DROPDOWN)[0] |
|||
|
|||
if (dropdownElement) { |
|||
const dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(SELECTOR_DROPDOWN_TOGGLE)) |
|||
|
|||
$(dropdownToggleList).addClass(CLASS_NAME_ACTIVE) |
|||
} |
|||
|
|||
element.setAttribute('aria-expanded', true) |
|||
} |
|||
|
|||
if (callback) { |
|||
callback() |
|||
} |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
const $this = $(this) |
|||
let data = $this.data(DATA_KEY) |
|||
|
|||
if (!data) { |
|||
data = new Tab(this) |
|||
$this.data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config]() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Data Api implementation |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$(document) |
|||
.on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { |
|||
event.preventDefault() |
|||
Tab._jQueryInterface.call($(this), 'show') |
|||
}) |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Tab._jQueryInterface |
|||
$.fn[NAME].Constructor = Tab |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Tab._jQueryInterface |
|||
} |
|||
|
|||
export default Tab |
@ -0,0 +1,230 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): toast.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'toast' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.toast' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
|
|||
const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}` |
|||
const EVENT_HIDE = `hide${EVENT_KEY}` |
|||
const EVENT_HIDDEN = `hidden${EVENT_KEY}` |
|||
const EVENT_SHOW = `show${EVENT_KEY}` |
|||
const EVENT_SHOWN = `shown${EVENT_KEY}` |
|||
|
|||
const CLASS_NAME_FADE = 'fade' |
|||
const CLASS_NAME_HIDE = 'hide' |
|||
const CLASS_NAME_SHOW = 'show' |
|||
const CLASS_NAME_SHOWING = 'showing' |
|||
|
|||
const DefaultType = { |
|||
animation: 'boolean', |
|||
autohide: 'boolean', |
|||
delay: 'number' |
|||
} |
|||
|
|||
const Default = { |
|||
animation: true, |
|||
autohide: true, |
|||
delay: 500 |
|||
} |
|||
|
|||
const SELECTOR_DATA_DISMISS = '[data-dismiss="toast"]' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Toast { |
|||
constructor(element, config) { |
|||
this._element = element |
|||
this._config = this._getConfig(config) |
|||
this._timeout = null |
|||
this._setListeners() |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get DefaultType() { |
|||
return DefaultType |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
show() { |
|||
const showEvent = $.Event(EVENT_SHOW) |
|||
|
|||
$(this._element).trigger(showEvent) |
|||
if (showEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
this._clearTimeout() |
|||
|
|||
if (this._config.animation) { |
|||
this._element.classList.add(CLASS_NAME_FADE) |
|||
} |
|||
|
|||
const complete = () => { |
|||
this._element.classList.remove(CLASS_NAME_SHOWING) |
|||
this._element.classList.add(CLASS_NAME_SHOW) |
|||
|
|||
$(this._element).trigger(EVENT_SHOWN) |
|||
|
|||
if (this._config.autohide) { |
|||
this._timeout = setTimeout(() => { |
|||
this.hide() |
|||
}, this._config.delay) |
|||
} |
|||
} |
|||
|
|||
this._element.classList.remove(CLASS_NAME_HIDE) |
|||
Util.reflow(this._element) |
|||
this._element.classList.add(CLASS_NAME_SHOWING) |
|||
if (this._config.animation) { |
|||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) |
|||
|
|||
$(this._element) |
|||
.one(Util.TRANSITION_END, complete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
complete() |
|||
} |
|||
} |
|||
|
|||
hide() { |
|||
if (!this._element.classList.contains(CLASS_NAME_SHOW)) { |
|||
return |
|||
} |
|||
|
|||
const hideEvent = $.Event(EVENT_HIDE) |
|||
|
|||
$(this._element).trigger(hideEvent) |
|||
if (hideEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
this._close() |
|||
} |
|||
|
|||
dispose() { |
|||
this._clearTimeout() |
|||
|
|||
if (this._element.classList.contains(CLASS_NAME_SHOW)) { |
|||
this._element.classList.remove(CLASS_NAME_SHOW) |
|||
} |
|||
|
|||
$(this._element).off(EVENT_CLICK_DISMISS) |
|||
|
|||
$.removeData(this._element, DATA_KEY) |
|||
this._element = null |
|||
this._config = null |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getConfig(config) { |
|||
config = { |
|||
...Default, |
|||
...$(this._element).data(), |
|||
...(typeof config === 'object' && config ? config : {}) |
|||
} |
|||
|
|||
Util.typeCheckConfig( |
|||
NAME, |
|||
config, |
|||
this.constructor.DefaultType |
|||
) |
|||
|
|||
return config |
|||
} |
|||
|
|||
_setListeners() { |
|||
$(this._element).on(EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, () => this.hide()) |
|||
} |
|||
|
|||
_close() { |
|||
const complete = () => { |
|||
this._element.classList.add(CLASS_NAME_HIDE) |
|||
$(this._element).trigger(EVENT_HIDDEN) |
|||
} |
|||
|
|||
this._element.classList.remove(CLASS_NAME_SHOW) |
|||
if (this._config.animation) { |
|||
const transitionDuration = Util.getTransitionDurationFromElement(this._element) |
|||
|
|||
$(this._element) |
|||
.one(Util.TRANSITION_END, complete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
complete() |
|||
} |
|||
} |
|||
|
|||
_clearTimeout() { |
|||
clearTimeout(this._timeout) |
|||
this._timeout = null |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
const $element = $(this) |
|||
let data = $element.data(DATA_KEY) |
|||
const _config = typeof config === 'object' && config |
|||
|
|||
if (!data) { |
|||
data = new Toast(this, _config) |
|||
$element.data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config](this) |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Toast._jQueryInterface |
|||
$.fn[NAME].Constructor = Toast |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Toast._jQueryInterface |
|||
} |
|||
|
|||
export default Toast |
@ -0,0 +1,127 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): tools/sanitizer.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
const uriAttrs = [ |
|||
'background', |
|||
'cite', |
|||
'href', |
|||
'itemtype', |
|||
'longdesc', |
|||
'poster', |
|||
'src', |
|||
'xlink:href' |
|||
] |
|||
|
|||
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i |
|||
|
|||
export const DefaultWhitelist = { |
|||
// Global attributes allowed on any supplied element below.
|
|||
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], |
|||
a: ['target', 'href', 'title', 'rel'], |
|||
area: [], |
|||
b: [], |
|||
br: [], |
|||
col: [], |
|||
code: [], |
|||
div: [], |
|||
em: [], |
|||
hr: [], |
|||
h1: [], |
|||
h2: [], |
|||
h3: [], |
|||
h4: [], |
|||
h5: [], |
|||
h6: [], |
|||
i: [], |
|||
img: ['src', 'srcset', 'alt', 'title', 'width', 'height'], |
|||
li: [], |
|||
ol: [], |
|||
p: [], |
|||
pre: [], |
|||
s: [], |
|||
small: [], |
|||
span: [], |
|||
sub: [], |
|||
sup: [], |
|||
strong: [], |
|||
u: [], |
|||
ul: [] |
|||
} |
|||
|
|||
/** |
|||
* A pattern that recognizes a commonly useful subset of URLs that are safe. |
|||
* |
|||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
|||
*/ |
|||
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/gi |
|||
|
|||
/** |
|||
* A pattern that matches safe data URLs. Only matches image, video and audio types. |
|||
* |
|||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
|||
*/ |
|||
const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i |
|||
|
|||
function allowedAttribute(attr, allowedAttributeList) { |
|||
const attrName = attr.nodeName.toLowerCase() |
|||
|
|||
if (allowedAttributeList.indexOf(attrName) !== -1) { |
|||
if (uriAttrs.indexOf(attrName) !== -1) { |
|||
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN)) |
|||
} |
|||
|
|||
return true |
|||
} |
|||
|
|||
const regExp = allowedAttributeList.filter(attrRegex => attrRegex instanceof RegExp) |
|||
|
|||
// Check if a regular expression validates the attribute.
|
|||
for (let i = 0, len = regExp.length; i < len; i++) { |
|||
if (attrName.match(regExp[i])) { |
|||
return true |
|||
} |
|||
} |
|||
|
|||
return false |
|||
} |
|||
|
|||
export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) { |
|||
if (unsafeHtml.length === 0) { |
|||
return unsafeHtml |
|||
} |
|||
|
|||
if (sanitizeFn && typeof sanitizeFn === 'function') { |
|||
return sanitizeFn(unsafeHtml) |
|||
} |
|||
|
|||
const domParser = new window.DOMParser() |
|||
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html') |
|||
const whitelistKeys = Object.keys(whiteList) |
|||
const elements = [].slice.call(createdDocument.body.querySelectorAll('*')) |
|||
|
|||
for (let i = 0, len = elements.length; i < len; i++) { |
|||
const el = elements[i] |
|||
const elName = el.nodeName.toLowerCase() |
|||
|
|||
if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) { |
|||
el.parentNode.removeChild(el) |
|||
|
|||
continue |
|||
} |
|||
|
|||
const attributeList = [].slice.call(el.attributes) |
|||
const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []) |
|||
|
|||
attributeList.forEach(attr => { |
|||
if (!allowedAttribute(attr, whitelistedAttributes)) { |
|||
el.removeAttribute(attr.nodeName) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
return createdDocument.body.innerHTML |
|||
} |
@ -0,0 +1,778 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): tooltip.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import { |
|||
DefaultWhitelist, |
|||
sanitizeHtml |
|||
} from './tools/sanitizer' |
|||
import $ from 'jquery' |
|||
import Popper from 'core/popper' |
|||
import Util from './util' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Constants |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const NAME = 'tooltip' |
|||
const VERSION = '4.6.0' |
|||
const DATA_KEY = 'bs.tooltip' |
|||
const EVENT_KEY = `.${DATA_KEY}` |
|||
const JQUERY_NO_CONFLICT = $.fn[NAME] |
|||
const CLASS_PREFIX = 'bs-tooltip' |
|||
const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') |
|||
const DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'] |
|||
|
|||
const DefaultType = { |
|||
animation: 'boolean', |
|||
template: 'string', |
|||
title: '(string|element|function)', |
|||
trigger: 'string', |
|||
delay: '(number|object)', |
|||
html: 'boolean', |
|||
selector: '(string|boolean)', |
|||
placement: '(string|function)', |
|||
offset: '(number|string|function)', |
|||
container: '(string|element|boolean)', |
|||
fallbackPlacement: '(string|array)', |
|||
boundary: '(string|element)', |
|||
customClass: '(string|function)', |
|||
sanitize: 'boolean', |
|||
sanitizeFn: '(null|function)', |
|||
whiteList: 'object', |
|||
popperConfig: '(null|object)' |
|||
} |
|||
|
|||
const AttachmentMap = { |
|||
AUTO: 'auto', |
|||
TOP: 'top', |
|||
RIGHT: 'right', |
|||
BOTTOM: 'bottom', |
|||
LEFT: 'left' |
|||
} |
|||
|
|||
const Default = { |
|||
animation: true, |
|||
template: '<div class="tooltip" role="tooltip">' + |
|||
'<div class="arrow"></div>' + |
|||
'<div class="tooltip-inner"></div></div>', |
|||
trigger: 'hover focus', |
|||
title: '', |
|||
delay: 0, |
|||
html: false, |
|||
selector: false, |
|||
placement: 'top', |
|||
offset: 0, |
|||
container: false, |
|||
fallbackPlacement: 'flip', |
|||
boundary: 'scrollParent', |
|||
customClass: '', |
|||
sanitize: true, |
|||
sanitizeFn: null, |
|||
whiteList: DefaultWhitelist, |
|||
popperConfig: null |
|||
} |
|||
|
|||
const HOVER_STATE_SHOW = 'show' |
|||
const HOVER_STATE_OUT = 'out' |
|||
|
|||
const Event = { |
|||
HIDE: `hide${EVENT_KEY}`, |
|||
HIDDEN: `hidden${EVENT_KEY}`, |
|||
SHOW: `show${EVENT_KEY}`, |
|||
SHOWN: `shown${EVENT_KEY}`, |
|||
INSERTED: `inserted${EVENT_KEY}`, |
|||
CLICK: `click${EVENT_KEY}`, |
|||
FOCUSIN: `focusin${EVENT_KEY}`, |
|||
FOCUSOUT: `focusout${EVENT_KEY}`, |
|||
MOUSEENTER: `mouseenter${EVENT_KEY}`, |
|||
MOUSELEAVE: `mouseleave${EVENT_KEY}` |
|||
} |
|||
|
|||
const CLASS_NAME_FADE = 'fade' |
|||
const CLASS_NAME_SHOW = 'show' |
|||
|
|||
const SELECTOR_TOOLTIP_INNER = '.tooltip-inner' |
|||
const SELECTOR_ARROW = '.arrow' |
|||
|
|||
const TRIGGER_HOVER = 'hover' |
|||
const TRIGGER_FOCUS = 'focus' |
|||
const TRIGGER_CLICK = 'click' |
|||
const TRIGGER_MANUAL = 'manual' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Class Definition |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
class Tooltip { |
|||
constructor(element, config) { |
|||
if (typeof Popper === 'undefined') { |
|||
throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)') |
|||
} |
|||
|
|||
// private
|
|||
this._isEnabled = true |
|||
this._timeout = 0 |
|||
this._hoverState = '' |
|||
this._activeTrigger = {} |
|||
this._popper = null |
|||
|
|||
// Protected
|
|||
this.element = element |
|||
this.config = this._getConfig(config) |
|||
this.tip = null |
|||
|
|||
this._setListeners() |
|||
} |
|||
|
|||
// Getters
|
|||
|
|||
static get VERSION() { |
|||
return VERSION |
|||
} |
|||
|
|||
static get Default() { |
|||
return Default |
|||
} |
|||
|
|||
static get NAME() { |
|||
return NAME |
|||
} |
|||
|
|||
static get DATA_KEY() { |
|||
return DATA_KEY |
|||
} |
|||
|
|||
static get Event() { |
|||
return Event |
|||
} |
|||
|
|||
static get EVENT_KEY() { |
|||
return EVENT_KEY |
|||
} |
|||
|
|||
static get DefaultType() { |
|||
return DefaultType |
|||
} |
|||
|
|||
// Public
|
|||
|
|||
enable() { |
|||
this._isEnabled = true |
|||
} |
|||
|
|||
disable() { |
|||
this._isEnabled = false |
|||
} |
|||
|
|||
toggleEnabled() { |
|||
this._isEnabled = !this._isEnabled |
|||
} |
|||
|
|||
toggle(event) { |
|||
if (!this._isEnabled) { |
|||
return |
|||
} |
|||
|
|||
if (event) { |
|||
const dataKey = this.constructor.DATA_KEY |
|||
let context = $(event.currentTarget).data(dataKey) |
|||
|
|||
if (!context) { |
|||
context = new this.constructor( |
|||
event.currentTarget, |
|||
this._getDelegateConfig() |
|||
) |
|||
$(event.currentTarget).data(dataKey, context) |
|||
} |
|||
|
|||
context._activeTrigger.click = !context._activeTrigger.click |
|||
|
|||
if (context._isWithActiveTrigger()) { |
|||
context._enter(null, context) |
|||
} else { |
|||
context._leave(null, context) |
|||
} |
|||
} else { |
|||
if ($(this.getTipElement()).hasClass(CLASS_NAME_SHOW)) { |
|||
this._leave(null, this) |
|||
return |
|||
} |
|||
|
|||
this._enter(null, this) |
|||
} |
|||
} |
|||
|
|||
dispose() { |
|||
clearTimeout(this._timeout) |
|||
|
|||
$.removeData(this.element, this.constructor.DATA_KEY) |
|||
|
|||
$(this.element).off(this.constructor.EVENT_KEY) |
|||
$(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler) |
|||
|
|||
if (this.tip) { |
|||
$(this.tip).remove() |
|||
} |
|||
|
|||
this._isEnabled = null |
|||
this._timeout = null |
|||
this._hoverState = null |
|||
this._activeTrigger = null |
|||
if (this._popper) { |
|||
this._popper.destroy() |
|||
} |
|||
|
|||
this._popper = null |
|||
this.element = null |
|||
this.config = null |
|||
this.tip = null |
|||
} |
|||
|
|||
show() { |
|||
if ($(this.element).css('display') === 'none') { |
|||
throw new Error('Please use show on visible elements') |
|||
} |
|||
|
|||
const showEvent = $.Event(this.constructor.Event.SHOW) |
|||
if (this.isWithContent() && this._isEnabled) { |
|||
$(this.element).trigger(showEvent) |
|||
|
|||
const shadowRoot = Util.findShadowRoot(this.element) |
|||
const isInTheDom = $.contains( |
|||
shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, |
|||
this.element |
|||
) |
|||
|
|||
if (showEvent.isDefaultPrevented() || !isInTheDom) { |
|||
return |
|||
} |
|||
|
|||
const tip = this.getTipElement() |
|||
const tipId = Util.getUID(this.constructor.NAME) |
|||
|
|||
tip.setAttribute('id', tipId) |
|||
this.element.setAttribute('aria-describedby', tipId) |
|||
|
|||
this.setContent() |
|||
|
|||
if (this.config.animation) { |
|||
$(tip).addClass(CLASS_NAME_FADE) |
|||
} |
|||
|
|||
const placement = typeof this.config.placement === 'function' ? |
|||
this.config.placement.call(this, tip, this.element) : |
|||
this.config.placement |
|||
|
|||
const attachment = this._getAttachment(placement) |
|||
this.addAttachmentClass(attachment) |
|||
|
|||
const container = this._getContainer() |
|||
$(tip).data(this.constructor.DATA_KEY, this) |
|||
|
|||
if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) { |
|||
$(tip).appendTo(container) |
|||
} |
|||
|
|||
$(this.element).trigger(this.constructor.Event.INSERTED) |
|||
|
|||
this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment)) |
|||
|
|||
$(tip).addClass(CLASS_NAME_SHOW) |
|||
$(tip).addClass(this.config.customClass) |
|||
|
|||
// If this is a touch-enabled device we add extra
|
|||
// empty mouseover listeners to the body's immediate children;
|
|||
// only needed because of broken event delegation on iOS
|
|||
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
|||
if ('ontouchstart' in document.documentElement) { |
|||
$(document.body).children().on('mouseover', null, $.noop) |
|||
} |
|||
|
|||
const complete = () => { |
|||
if (this.config.animation) { |
|||
this._fixTransition() |
|||
} |
|||
|
|||
const prevHoverState = this._hoverState |
|||
this._hoverState = null |
|||
|
|||
$(this.element).trigger(this.constructor.Event.SHOWN) |
|||
|
|||
if (prevHoverState === HOVER_STATE_OUT) { |
|||
this._leave(null, this) |
|||
} |
|||
} |
|||
|
|||
if ($(this.tip).hasClass(CLASS_NAME_FADE)) { |
|||
const transitionDuration = Util.getTransitionDurationFromElement(this.tip) |
|||
|
|||
$(this.tip) |
|||
.one(Util.TRANSITION_END, complete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
complete() |
|||
} |
|||
} |
|||
} |
|||
|
|||
hide(callback) { |
|||
const tip = this.getTipElement() |
|||
const hideEvent = $.Event(this.constructor.Event.HIDE) |
|||
const complete = () => { |
|||
if (this._hoverState !== HOVER_STATE_SHOW && tip.parentNode) { |
|||
tip.parentNode.removeChild(tip) |
|||
} |
|||
|
|||
this._cleanTipClass() |
|||
this.element.removeAttribute('aria-describedby') |
|||
$(this.element).trigger(this.constructor.Event.HIDDEN) |
|||
if (this._popper !== null) { |
|||
this._popper.destroy() |
|||
} |
|||
|
|||
if (callback) { |
|||
callback() |
|||
} |
|||
} |
|||
|
|||
$(this.element).trigger(hideEvent) |
|||
|
|||
if (hideEvent.isDefaultPrevented()) { |
|||
return |
|||
} |
|||
|
|||
$(tip).removeClass(CLASS_NAME_SHOW) |
|||
|
|||
// If this is a touch-enabled device we remove the extra
|
|||
// empty mouseover listeners we added for iOS support
|
|||
if ('ontouchstart' in document.documentElement) { |
|||
$(document.body).children().off('mouseover', null, $.noop) |
|||
} |
|||
|
|||
this._activeTrigger[TRIGGER_CLICK] = false |
|||
this._activeTrigger[TRIGGER_FOCUS] = false |
|||
this._activeTrigger[TRIGGER_HOVER] = false |
|||
|
|||
if ($(this.tip).hasClass(CLASS_NAME_FADE)) { |
|||
const transitionDuration = Util.getTransitionDurationFromElement(tip) |
|||
|
|||
$(tip) |
|||
.one(Util.TRANSITION_END, complete) |
|||
.emulateTransitionEnd(transitionDuration) |
|||
} else { |
|||
complete() |
|||
} |
|||
|
|||
this._hoverState = '' |
|||
} |
|||
|
|||
update() { |
|||
if (this._popper !== null) { |
|||
this._popper.scheduleUpdate() |
|||
} |
|||
} |
|||
|
|||
// Protected
|
|||
|
|||
isWithContent() { |
|||
return Boolean(this.getTitle()) |
|||
} |
|||
|
|||
addAttachmentClass(attachment) { |
|||
$(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) |
|||
} |
|||
|
|||
getTipElement() { |
|||
this.tip = this.tip || $(this.config.template)[0] |
|||
return this.tip |
|||
} |
|||
|
|||
setContent() { |
|||
const tip = this.getTipElement() |
|||
this.setElementContent($(tip.querySelectorAll(SELECTOR_TOOLTIP_INNER)), this.getTitle()) |
|||
$(tip).removeClass(`${CLASS_NAME_FADE} ${CLASS_NAME_SHOW}`) |
|||
} |
|||
|
|||
setElementContent($element, content) { |
|||
if (typeof content === 'object' && (content.nodeType || content.jquery)) { |
|||
// Content is a DOM node or a jQuery
|
|||
if (this.config.html) { |
|||
if (!$(content).parent().is($element)) { |
|||
$element.empty().append(content) |
|||
} |
|||
} else { |
|||
$element.text($(content).text()) |
|||
} |
|||
|
|||
return |
|||
} |
|||
|
|||
if (this.config.html) { |
|||
if (this.config.sanitize) { |
|||
content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn) |
|||
} |
|||
|
|||
$element.html(content) |
|||
} else { |
|||
$element.text(content) |
|||
} |
|||
} |
|||
|
|||
getTitle() { |
|||
let title = this.element.getAttribute('data-original-title') |
|||
|
|||
if (!title) { |
|||
title = typeof this.config.title === 'function' ? |
|||
this.config.title.call(this.element) : |
|||
this.config.title |
|||
} |
|||
|
|||
return title |
|||
} |
|||
|
|||
// Private
|
|||
|
|||
_getPopperConfig(attachment) { |
|||
const defaultBsConfig = { |
|||
placement: attachment, |
|||
modifiers: { |
|||
offset: this._getOffset(), |
|||
flip: { |
|||
behavior: this.config.fallbackPlacement |
|||
}, |
|||
arrow: { |
|||
element: SELECTOR_ARROW |
|||
}, |
|||
preventOverflow: { |
|||
boundariesElement: this.config.boundary |
|||
} |
|||
}, |
|||
onCreate: data => { |
|||
if (data.originalPlacement !== data.placement) { |
|||
this._handlePopperPlacementChange(data) |
|||
} |
|||
}, |
|||
onUpdate: data => this._handlePopperPlacementChange(data) |
|||
} |
|||
|
|||
return { |
|||
...defaultBsConfig, |
|||
...this.config.popperConfig |
|||
} |
|||
} |
|||
|
|||
_getOffset() { |
|||
const offset = {} |
|||
|
|||
if (typeof this.config.offset === 'function') { |
|||
offset.fn = data => { |
|||
data.offsets = { |
|||
...data.offsets, |
|||
...(this.config.offset(data.offsets, this.element) || {}) |
|||
} |
|||
|
|||
return data |
|||
} |
|||
} else { |
|||
offset.offset = this.config.offset |
|||
} |
|||
|
|||
return offset |
|||
} |
|||
|
|||
_getContainer() { |
|||
if (this.config.container === false) { |
|||
return document.body |
|||
} |
|||
|
|||
if (Util.isElement(this.config.container)) { |
|||
return $(this.config.container) |
|||
} |
|||
|
|||
return $(document).find(this.config.container) |
|||
} |
|||
|
|||
_getAttachment(placement) { |
|||
return AttachmentMap[placement.toUpperCase()] |
|||
} |
|||
|
|||
_setListeners() { |
|||
const triggers = this.config.trigger.split(' ') |
|||
|
|||
triggers.forEach(trigger => { |
|||
if (trigger === 'click') { |
|||
$(this.element).on( |
|||
this.constructor.Event.CLICK, |
|||
this.config.selector, |
|||
event => this.toggle(event) |
|||
) |
|||
} else if (trigger !== TRIGGER_MANUAL) { |
|||
const eventIn = trigger === TRIGGER_HOVER ? |
|||
this.constructor.Event.MOUSEENTER : |
|||
this.constructor.Event.FOCUSIN |
|||
const eventOut = trigger === TRIGGER_HOVER ? |
|||
this.constructor.Event.MOUSELEAVE : |
|||
this.constructor.Event.FOCUSOUT |
|||
|
|||
$(this.element) |
|||
.on(eventIn, this.config.selector, event => this._enter(event)) |
|||
.on(eventOut, this.config.selector, event => this._leave(event)) |
|||
} |
|||
}) |
|||
|
|||
this._hideModalHandler = () => { |
|||
if (this.element) { |
|||
this.hide() |
|||
} |
|||
} |
|||
|
|||
$(this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler) |
|||
|
|||
if (this.config.selector) { |
|||
this.config = { |
|||
...this.config, |
|||
trigger: 'manual', |
|||
selector: '' |
|||
} |
|||
} else { |
|||
this._fixTitle() |
|||
} |
|||
} |
|||
|
|||
_fixTitle() { |
|||
const titleType = typeof this.element.getAttribute('data-original-title') |
|||
|
|||
if (this.element.getAttribute('title') || titleType !== 'string') { |
|||
this.element.setAttribute( |
|||
'data-original-title', |
|||
this.element.getAttribute('title') || '' |
|||
) |
|||
|
|||
this.element.setAttribute('title', '') |
|||
} |
|||
} |
|||
|
|||
_enter(event, context) { |
|||
const dataKey = this.constructor.DATA_KEY |
|||
context = context || $(event.currentTarget).data(dataKey) |
|||
|
|||
if (!context) { |
|||
context = new this.constructor( |
|||
event.currentTarget, |
|||
this._getDelegateConfig() |
|||
) |
|||
$(event.currentTarget).data(dataKey, context) |
|||
} |
|||
|
|||
if (event) { |
|||
context._activeTrigger[ |
|||
event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER |
|||
] = true |
|||
} |
|||
|
|||
if ($(context.getTipElement()).hasClass(CLASS_NAME_SHOW) || context._hoverState === HOVER_STATE_SHOW) { |
|||
context._hoverState = HOVER_STATE_SHOW |
|||
return |
|||
} |
|||
|
|||
clearTimeout(context._timeout) |
|||
|
|||
context._hoverState = HOVER_STATE_SHOW |
|||
|
|||
if (!context.config.delay || !context.config.delay.show) { |
|||
context.show() |
|||
return |
|||
} |
|||
|
|||
context._timeout = setTimeout(() => { |
|||
if (context._hoverState === HOVER_STATE_SHOW) { |
|||
context.show() |
|||
} |
|||
}, context.config.delay.show) |
|||
} |
|||
|
|||
_leave(event, context) { |
|||
const dataKey = this.constructor.DATA_KEY |
|||
context = context || $(event.currentTarget).data(dataKey) |
|||
|
|||
if (!context) { |
|||
context = new this.constructor( |
|||
event.currentTarget, |
|||
this._getDelegateConfig() |
|||
) |
|||
$(event.currentTarget).data(dataKey, context) |
|||
} |
|||
|
|||
if (event) { |
|||
context._activeTrigger[ |
|||
event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER |
|||
] = false |
|||
} |
|||
|
|||
if (context._isWithActiveTrigger()) { |
|||
return |
|||
} |
|||
|
|||
clearTimeout(context._timeout) |
|||
|
|||
context._hoverState = HOVER_STATE_OUT |
|||
|
|||
if (!context.config.delay || !context.config.delay.hide) { |
|||
context.hide() |
|||
return |
|||
} |
|||
|
|||
context._timeout = setTimeout(() => { |
|||
if (context._hoverState === HOVER_STATE_OUT) { |
|||
context.hide() |
|||
} |
|||
}, context.config.delay.hide) |
|||
} |
|||
|
|||
_isWithActiveTrigger() { |
|||
for (const trigger in this._activeTrigger) { |
|||
if (this._activeTrigger[trigger]) { |
|||
return true |
|||
} |
|||
} |
|||
|
|||
return false |
|||
} |
|||
|
|||
_getConfig(config) { |
|||
const dataAttributes = $(this.element).data() |
|||
|
|||
Object.keys(dataAttributes) |
|||
.forEach(dataAttr => { |
|||
if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) { |
|||
delete dataAttributes[dataAttr] |
|||
} |
|||
}) |
|||
|
|||
config = { |
|||
...this.constructor.Default, |
|||
...dataAttributes, |
|||
...(typeof config === 'object' && config ? config : {}) |
|||
} |
|||
|
|||
if (typeof config.delay === 'number') { |
|||
config.delay = { |
|||
show: config.delay, |
|||
hide: config.delay |
|||
} |
|||
} |
|||
|
|||
if (typeof config.title === 'number') { |
|||
config.title = config.title.toString() |
|||
} |
|||
|
|||
if (typeof config.content === 'number') { |
|||
config.content = config.content.toString() |
|||
} |
|||
|
|||
Util.typeCheckConfig( |
|||
NAME, |
|||
config, |
|||
this.constructor.DefaultType |
|||
) |
|||
|
|||
if (config.sanitize) { |
|||
config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn) |
|||
} |
|||
|
|||
return config |
|||
} |
|||
|
|||
_getDelegateConfig() { |
|||
const config = {} |
|||
|
|||
if (this.config) { |
|||
for (const key in this.config) { |
|||
if (this.constructor.Default[key] !== this.config[key]) { |
|||
config[key] = this.config[key] |
|||
} |
|||
} |
|||
} |
|||
|
|||
return config |
|||
} |
|||
|
|||
_cleanTipClass() { |
|||
const $tip = $(this.getTipElement()) |
|||
const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) |
|||
if (tabClass !== null && tabClass.length) { |
|||
$tip.removeClass(tabClass.join('')) |
|||
} |
|||
} |
|||
|
|||
_handlePopperPlacementChange(popperData) { |
|||
this.tip = popperData.instance.popper |
|||
this._cleanTipClass() |
|||
this.addAttachmentClass(this._getAttachment(popperData.placement)) |
|||
} |
|||
|
|||
_fixTransition() { |
|||
const tip = this.getTipElement() |
|||
const initConfigAnimation = this.config.animation |
|||
|
|||
if (tip.getAttribute('x-placement') !== null) { |
|||
return |
|||
} |
|||
|
|||
$(tip).removeClass(CLASS_NAME_FADE) |
|||
this.config.animation = false |
|||
this.hide() |
|||
this.show() |
|||
this.config.animation = initConfigAnimation |
|||
} |
|||
|
|||
// Static
|
|||
|
|||
static _jQueryInterface(config) { |
|||
return this.each(function () { |
|||
const $element = $(this) |
|||
let data = $element.data(DATA_KEY) |
|||
const _config = typeof config === 'object' && config |
|||
|
|||
if (!data && /dispose|hide/.test(config)) { |
|||
return |
|||
} |
|||
|
|||
if (!data) { |
|||
data = new Tooltip(this, _config) |
|||
$element.data(DATA_KEY, data) |
|||
} |
|||
|
|||
if (typeof config === 'string') { |
|||
if (typeof data[config] === 'undefined') { |
|||
throw new TypeError(`No method named "${config}"`) |
|||
} |
|||
|
|||
data[config]() |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* jQuery |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
$.fn[NAME] = Tooltip._jQueryInterface |
|||
$.fn[NAME].Constructor = Tooltip |
|||
$.fn[NAME].noConflict = () => { |
|||
$.fn[NAME] = JQUERY_NO_CONFLICT |
|||
return Tooltip._jQueryInterface |
|||
} |
|||
|
|||
export default Tooltip |
@ -0,0 +1,198 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): util.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import $ from 'jquery' |
|||
|
|||
/** |
|||
* ------------------------------------------------------------------------ |
|||
* Private TransitionEnd Helpers |
|||
* ------------------------------------------------------------------------ |
|||
*/ |
|||
|
|||
const TRANSITION_END = 'transitionend' |
|||
const MAX_UID = 1000000 |
|||
const MILLISECONDS_MULTIPLIER = 1000 |
|||
|
|||
// Shoutout AngusCroll (https://goo.gl/pxwQGp)
|
|||
function toType(obj) { |
|||
if (obj === null || typeof obj === 'undefined') { |
|||
return `${obj}` |
|||
} |
|||
|
|||
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase() |
|||
} |
|||
|
|||
function getSpecialTransitionEndEvent() { |
|||
return { |
|||
bindType: TRANSITION_END, |
|||
delegateType: TRANSITION_END, |
|||
handle(event) { |
|||
if ($(event.target).is(this)) { |
|||
return event.handleObj.handler.apply(this, arguments) // eslint-disable-line prefer-rest-params
|
|||
} |
|||
|
|||
return undefined |
|||
} |
|||
} |
|||
} |
|||
|
|||
function transitionEndEmulator(duration) { |
|||
let called = false |
|||
|
|||
$(this).one(Util.TRANSITION_END, () => { |
|||
called = true |
|||
}) |
|||
|
|||
setTimeout(() => { |
|||
if (!called) { |
|||
Util.triggerTransitionEnd(this) |
|||
} |
|||
}, duration) |
|||
|
|||
return this |
|||
} |
|||
|
|||
function setTransitionEndSupport() { |
|||
$.fn.emulateTransitionEnd = transitionEndEmulator |
|||
$.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent() |
|||
} |
|||
|
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Public Util Api |
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
const Util = { |
|||
TRANSITION_END: 'bsTransitionEnd', |
|||
|
|||
getUID(prefix) { |
|||
do { |
|||
prefix += ~~(Math.random() * MAX_UID) // "~~" acts like a faster Math.floor() here
|
|||
} while (document.getElementById(prefix)) |
|||
|
|||
return prefix |
|||
}, |
|||
|
|||
getSelectorFromElement(element) { |
|||
let selector = element.getAttribute('data-target') |
|||
|
|||
if (!selector || selector === '#') { |
|||
const hrefAttr = element.getAttribute('href') |
|||
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '' |
|||
} |
|||
|
|||
try { |
|||
return document.querySelector(selector) ? selector : null |
|||
} catch (_) { |
|||
return null |
|||
} |
|||
}, |
|||
|
|||
getTransitionDurationFromElement(element) { |
|||
if (!element) { |
|||
return 0 |
|||
} |
|||
|
|||
// Get transition-duration of the element
|
|||
let transitionDuration = $(element).css('transition-duration') |
|||
let transitionDelay = $(element).css('transition-delay') |
|||
|
|||
const floatTransitionDuration = parseFloat(transitionDuration) |
|||
const floatTransitionDelay = parseFloat(transitionDelay) |
|||
|
|||
// Return 0 if element or transition duration is not found
|
|||
if (!floatTransitionDuration && !floatTransitionDelay) { |
|||
return 0 |
|||
} |
|||
|
|||
// If multiple durations are defined, take the first
|
|||
transitionDuration = transitionDuration.split(',')[0] |
|||
transitionDelay = transitionDelay.split(',')[0] |
|||
|
|||
return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER |
|||
}, |
|||
|
|||
reflow(element) { |
|||
return element.offsetHeight |
|||
}, |
|||
|
|||
triggerTransitionEnd(element) { |
|||
$(element).trigger(TRANSITION_END) |
|||
}, |
|||
|
|||
supportsTransitionEnd() { |
|||
return Boolean(TRANSITION_END) |
|||
}, |
|||
|
|||
isElement(obj) { |
|||
return (obj[0] || obj).nodeType |
|||
}, |
|||
|
|||
typeCheckConfig(componentName, config, configTypes) { |
|||
for (const property in configTypes) { |
|||
if (Object.prototype.hasOwnProperty.call(configTypes, property)) { |
|||
const expectedTypes = configTypes[property] |
|||
const value = config[property] |
|||
const valueType = value && Util.isElement(value) ? |
|||
'element' : toType(value) |
|||
|
|||
if (!new RegExp(expectedTypes).test(valueType)) { |
|||
throw new Error( |
|||
`${componentName.toUpperCase()}: ` + |
|||
`Option "${property}" provided type "${valueType}" ` + |
|||
`but expected type "${expectedTypes}".`) |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
|
|||
findShadowRoot(element) { |
|||
if (!document.documentElement.attachShadow) { |
|||
return null |
|||
} |
|||
|
|||
// Can find the shadow root otherwise it'll return the document
|
|||
if (typeof element.getRootNode === 'function') { |
|||
const root = element.getRootNode() |
|||
return root instanceof ShadowRoot ? root : null |
|||
} |
|||
|
|||
if (element instanceof ShadowRoot) { |
|||
return element |
|||
} |
|||
|
|||
// when we don't find a shadow root
|
|||
if (!element.parentNode) { |
|||
return null |
|||
} |
|||
|
|||
return Util.findShadowRoot(element.parentNode) |
|||
}, |
|||
|
|||
jQueryDetection() { |
|||
if (typeof $ === 'undefined') { |
|||
throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.') |
|||
} |
|||
|
|||
const version = $.fn.jquery.split(' ')[0].split('.') |
|||
const minMajor = 1 |
|||
const ltMajor = 2 |
|||
const minMinor = 9 |
|||
const minPatch = 1 |
|||
const maxMajor = 4 |
|||
|
|||
if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) { |
|||
throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0') |
|||
} |
|||
} |
|||
} |
|||
|
|||
Util.jQueryDetection() |
|||
setTransitionEndSupport() |
|||
|
|||
export default Util |
@ -0,0 +1,199 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Contain the logic for a drawer. |
|||
* |
|||
* @module theme_ilb/drawer |
|||
* @copyright 2016 Damyon Wiese |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
*/ |
|||
define(['jquery', 'core/custom_interaction_events', 'core/log', 'core/pubsub', 'core/aria'], |
|||
function($, CustomEvents, Log, PubSub, Aria) { |
|||
|
|||
var SELECTORS = { |
|||
TOGGLE_REGION: '[data-region="drawer-toggle"]', |
|||
TOGGLE_ACTION: '[data-action="toggle-drawer"]', |
|||
TOGGLE_TARGET: 'aria-controls', |
|||
TOGGLE_SIDE: 'left', |
|||
BODY: 'body', |
|||
SECTION: '.list-group-item[href*="#section-"]', |
|||
DRAWER: '#nav-drawer' |
|||
}; |
|||
|
|||
var small = $(document).width() < 768; |
|||
|
|||
/** |
|||
* Constructor for the Drawer. |
|||
*/ |
|||
var Drawer = function() { |
|||
|
|||
if (!$(SELECTORS.TOGGLE_REGION).length) { |
|||
Log.debug('Page is missing a drawer region'); |
|||
} |
|||
if (!$(SELECTORS.TOGGLE_ACTION).length) { |
|||
Log.debug('Page is missing a drawer toggle link'); |
|||
} |
|||
$(SELECTORS.TOGGLE_REGION).each(function(index, ele) { |
|||
var trigger = $(ele).find(SELECTORS.TOGGLE_ACTION); |
|||
var drawerid = trigger.attr('aria-controls'); |
|||
var drawer = $(document.getElementById(drawerid)); |
|||
var hidden = trigger.attr('aria-expanded') == 'false'; |
|||
var side = trigger.attr('data-side'); |
|||
var body = $(SELECTORS.BODY); |
|||
var preference = trigger.attr('data-preference'); |
|||
if (small) { |
|||
M.util.set_user_preference(preference, 'false'); |
|||
} |
|||
|
|||
drawer.on('mousewheel DOMMouseScroll', this.preventPageScroll); |
|||
|
|||
if (!hidden) { |
|||
body.addClass('drawer-open-' + side); |
|||
trigger.attr('aria-expanded', 'true'); |
|||
} else { |
|||
trigger.attr('aria-expanded', 'false'); |
|||
} |
|||
}.bind(this)); |
|||
|
|||
this.registerEventListeners(); |
|||
if (small) { |
|||
this.closeAll(); |
|||
} |
|||
}; |
|||
|
|||
Drawer.prototype.closeAll = function() { |
|||
$(SELECTORS.TOGGLE_REGION).each(function(index, ele) { |
|||
var trigger = $(ele).find(SELECTORS.TOGGLE_ACTION); |
|||
var side = trigger.attr('data-side'); |
|||
var body = $(SELECTORS.BODY); |
|||
var drawerid = trigger.attr('aria-controls'); |
|||
var drawer = $(document.getElementById(drawerid)); |
|||
var preference = trigger.attr('data-preference'); |
|||
|
|||
trigger.attr('aria-expanded', 'false'); |
|||
body.removeClass('drawer-open-' + side); |
|||
Aria.hide(drawer.get()); |
|||
drawer.addClass('closed'); |
|||
if (!small) { |
|||
M.util.set_user_preference(preference, 'false'); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* Open / close the blocks drawer. |
|||
* |
|||
* @method toggleDrawer |
|||
* @param {Event} e |
|||
*/ |
|||
Drawer.prototype.toggleDrawer = function(e) { |
|||
var trigger = $(e.target).closest('[data-action=toggle-drawer]'); |
|||
var drawerid = trigger.attr('aria-controls'); |
|||
var drawer = $(document.getElementById(drawerid)); |
|||
var body = $(SELECTORS.BODY); |
|||
var side = trigger.attr('data-side'); |
|||
var preference = trigger.attr('data-preference'); |
|||
if (small) { |
|||
M.util.set_user_preference(preference, 'false'); |
|||
} |
|||
|
|||
body.addClass('drawer-ease'); |
|||
var open = trigger.attr('aria-expanded') == 'true'; |
|||
if (!open) { |
|||
// Open.
|
|||
trigger.attr('aria-expanded', 'true'); |
|||
Aria.unhide(drawer.get()); |
|||
drawer.focus(); |
|||
body.addClass('drawer-open-' + side); |
|||
drawer.removeClass('closed'); |
|||
if (!small) { |
|||
M.util.set_user_preference(preference, 'true'); |
|||
} |
|||
} else { |
|||
// Close.
|
|||
body.removeClass('drawer-open-' + side); |
|||
trigger.attr('aria-expanded', 'false'); |
|||
drawer.addClass('closed').delay(500).queue(function() { |
|||
// Ensure that during the delay, the drawer wasn't re-opened.
|
|||
if ($(this).hasClass('closed')) { |
|||
Aria.hide(this); |
|||
} |
|||
$(this).dequeue(); |
|||
}); |
|||
if (!small) { |
|||
M.util.set_user_preference(preference, 'false'); |
|||
} |
|||
} |
|||
|
|||
// Publish an event to tell everything that the drawer has been toggled.
|
|||
// The drawer transitions closed so another event will fire once teh transition
|
|||
// has completed.
|
|||
PubSub.publish('nav-drawer-toggle-start', open); |
|||
}; |
|||
|
|||
/** |
|||
* Prevent the page from scrolling when the drawer is at max scroll. |
|||
* |
|||
* @method preventPageScroll |
|||
* @param {Event} e |
|||
*/ |
|||
Drawer.prototype.preventPageScroll = function(e) { |
|||
var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.originalEvent.detail, |
|||
bottomOverflow = (this.scrollTop + $(this).outerHeight() - this.scrollHeight) >= 0, |
|||
topOverflow = this.scrollTop <= 0; |
|||
|
|||
if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) { |
|||
e.preventDefault(); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Set up all of the event handling for the modal. |
|||
* |
|||
* @method registerEventListeners |
|||
*/ |
|||
Drawer.prototype.registerEventListeners = function() { |
|||
|
|||
$(SELECTORS.TOGGLE_ACTION).each(function(index, element) { |
|||
CustomEvents.define($(element), [CustomEvents.events.activate]); |
|||
$(element).on(CustomEvents.events.activate, function(e, data) { |
|||
this.toggleDrawer(data.originalEvent); |
|||
data.originalEvent.preventDefault(); |
|||
}.bind(this)); |
|||
}.bind(this)); |
|||
|
|||
$(SELECTORS.SECTION).click(function() { |
|||
if (small) { |
|||
this.closeAll(); |
|||
} |
|||
}.bind(this)); |
|||
|
|||
// Publish an event to tell everything that the drawer completed the transition
|
|||
// to either an open or closed state.
|
|||
$(SELECTORS.DRAWER).on('webkitTransitionEnd msTransitionEnd transitionend', function(e) { |
|||
var drawer = $(e.target).closest(SELECTORS.DRAWER); |
|||
// Note: aria-hidden is either present, or absent. It should not be set to false.
|
|||
var open = !!drawer.attr('aria-hidden'); |
|||
PubSub.publish('nav-drawer-toggle-end', open); |
|||
}); |
|||
}; |
|||
|
|||
return { |
|||
'init': function() { |
|||
return new Drawer(); |
|||
} |
|||
}; |
|||
}); |
@ -0,0 +1,114 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Custom form error event handler to manipulate the bootstrap markup and show |
|||
* nicely styled errors in an mform. |
|||
* |
|||
* @module theme_ilb/form-display-errors |
|||
* @copyright 2016 Damyon Wiese <damyon@moodle.com> |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
*/ |
|||
define(['jquery', 'core/event'], function($, Event) { |
|||
return { |
|||
enhance: function(elementid) { |
|||
var element = document.getElementById(elementid); |
|||
if (!element) { |
|||
// Some elements (e.g. static) don't have a form field.
|
|||
// Hence there is no validation. So, no setup required here.
|
|||
return; |
|||
} |
|||
|
|||
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) { |
|||
event.preventDefault(); |
|||
var parent = $(element).closest('.form-group'); |
|||
var feedback = parent.find('.form-control-feedback'); |
|||
const feedbackId = feedback.attr('id'); |
|||
|
|||
// Get current aria-describedby value.
|
|||
let describedBy = $(element).attr('aria-describedby'); |
|||
if (typeof describedBy === "undefined") { |
|||
describedBy = ''; |
|||
} |
|||
// Split aria-describedby attribute into an array of IDs if necessary.
|
|||
let describedByIds = []; |
|||
if (describedBy.length) { |
|||
describedByIds = describedBy.split(" "); |
|||
} |
|||
// Find the the feedback container in the aria-describedby attribute.
|
|||
const feedbackIndex = describedByIds.indexOf(feedbackId); |
|||
|
|||
// Sometimes (atto) we have a hidden textarea backed by a real contenteditable div.
|
|||
if (($(element).prop("tagName") == 'TEXTAREA') && parent.find('[contenteditable]')) { |
|||
element = parent.find('[contenteditable]'); |
|||
} |
|||
if (msg !== '') { |
|||
parent.addClass('has-danger'); |
|||
parent.data('client-validation-error', true); |
|||
$(element).addClass('is-invalid'); |
|||
// Append the feedback ID to the aria-describedby attribute if it doesn't exist yet.
|
|||
if (feedbackIndex === -1) { |
|||
describedByIds.push(feedbackId); |
|||
$(element).attr('aria-describedby', describedByIds.join(" ")); |
|||
} |
|||
$(element).attr('aria-invalid', true); |
|||
feedback.attr('tabindex', 0); |
|||
feedback.html(msg); |
|||
|
|||
// Only display and focus when the error was not already visible.
|
|||
// This is so that, when tabbing around the form, you don't get stuck.
|
|||
if (!feedback.is(':visible')) { |
|||
feedback.show(); |
|||
feedback.focus(); |
|||
} |
|||
|
|||
} else { |
|||
if (parent.data('client-validation-error') === true) { |
|||
parent.removeClass('has-danger'); |
|||
parent.data('client-validation-error', false); |
|||
$(element).removeClass('is-invalid'); |
|||
// If the aria-describedby attribute contains the error container's ID, remove it.
|
|||
if (feedbackIndex > -1) { |
|||
describedByIds.splice(feedbackIndex, 1); |
|||
} |
|||
// Check the remaining element IDs in the aria-describedby attribute.
|
|||
if (describedByIds.length) { |
|||
// If there's at least one, combine them with a blank space and update the aria-describedby attribute.
|
|||
describedBy = describedByIds.join(" "); |
|||
// Put back the new describedby attribute.
|
|||
$(element).attr('aria-describedby', describedBy); |
|||
} else { |
|||
// If there's none, remove the aria-describedby attribute.
|
|||
$(element).removeAttr('aria-describedby'); |
|||
} |
|||
$(element).attr('aria-invalid', false); |
|||
feedback.hide(); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
var form = element.closest('form'); |
|||
if (form && !('ilbFormErrorsEnhanced' in form.dataset)) { |
|||
form.addEventListener('submit', function() { |
|||
var visibleError = $('.form-control-feedback:visible'); |
|||
if (visibleError.length) { |
|||
visibleError[0].focus(); |
|||
} |
|||
}); |
|||
form.dataset.ilbFormErrorsEnhanced = 1; |
|||
} |
|||
} |
|||
}; |
|||
}); |
@ -0,0 +1,34 @@ |
|||
/** |
|||
* -------------------------------------------------------------------------- |
|||
* Bootstrap (v4.6.0): index.js |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
|||
* -------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
import Alert from './bootstrap/alert'; |
|||
import Button from './bootstrap/button'; |
|||
import Carousel from './bootstrap/carousel'; |
|||
import Collapse from './bootstrap/collapse'; |
|||
import Dropdown from './bootstrap/dropdown'; |
|||
import Modal from './bootstrap/modal'; |
|||
import Popover from './bootstrap/popover'; |
|||
import Scrollspy from './bootstrap/scrollspy'; |
|||
import Tab from './bootstrap/tab'; |
|||
import Toast from './bootstrap/toast'; |
|||
import Tooltip from './bootstrap/tooltip'; |
|||
import Util from './bootstrap/util'; |
|||
|
|||
export { |
|||
Util, |
|||
Alert, |
|||
Button, |
|||
Carousel, |
|||
Collapse, |
|||
Dropdown, |
|||
Modal, |
|||
Popover, |
|||
Scrollspy, |
|||
Tab, |
|||
Toast, |
|||
Tooltip |
|||
}; |
@ -0,0 +1,109 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Template renderer for Moodle. Load and render Moodle templates with Mustache. |
|||
* |
|||
* @module theme_ilb/loader |
|||
* @copyright 2015 Damyon Wiese <damyon@moodle.com> |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
* @since 2.9 |
|||
*/ |
|||
|
|||
import $ from 'jquery'; |
|||
import * as Aria from './aria'; |
|||
import Bootstrap from './index'; |
|||
import Pending from 'core/pending'; |
|||
import Scroll from './scroll'; |
|||
import setupBootstrapPendingChecks from './pending'; |
|||
|
|||
/** |
|||
* Rember the last visited tabs. |
|||
*/ |
|||
const rememberTabs = () => { |
|||
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { |
|||
var hash = $(e.target).attr('href'); |
|||
if (history.replaceState) { |
|||
history.replaceState(null, null, hash); |
|||
} else { |
|||
location.hash = hash; |
|||
} |
|||
}); |
|||
const hash = window.location.hash; |
|||
if (hash) { |
|||
const tab = document.querySelector('.nav-link[href="' + hash + '"]'); |
|||
if (tab) { |
|||
tab.click(); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Enable all popovers |
|||
* |
|||
*/ |
|||
const enablePopovers = () => { |
|||
$('body').popover({ |
|||
container: 'body', |
|||
selector: '[data-toggle="popover"]', |
|||
trigger: 'focus', |
|||
}); |
|||
|
|||
document.addEventListener('keydown', e => { |
|||
if (e.key === 'Escape' && e.target.closest('[data-toggle="popover"]')) { |
|||
$(e.target).popover('hide'); |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* Enable tooltips |
|||
* |
|||
*/ |
|||
const enableTooltips = () => { |
|||
$('body').tooltip({ |
|||
container: 'body', |
|||
selector: '[data-toggle="tooltip"]', |
|||
}); |
|||
}; |
|||
|
|||
const pendingPromise = new Pending('theme_ilb/loader:init'); |
|||
|
|||
// Add pending promise event listeners to relevant Bootstrap custom events.
|
|||
setupBootstrapPendingChecks(); |
|||
|
|||
// Setup Aria helpers for Bootstrap features.
|
|||
Aria.init(); |
|||
|
|||
// Remember the last visited tabs.
|
|||
rememberTabs(); |
|||
|
|||
// Enable all popovers.
|
|||
enablePopovers(); |
|||
|
|||
// Enable all tooltips.
|
|||
enableTooltips(); |
|||
|
|||
// Add scroll handling.
|
|||
(new Scroll()).init(); |
|||
|
|||
// Disables flipping the dropdowns up and getting hidden behind the navbar.
|
|||
$.fn.dropdown.Constructor.Default.flip = false; |
|||
|
|||
pendingPromise.resolve(); |
|||
|
|||
export { |
|||
Bootstrap, |
|||
}; |
@ -0,0 +1,133 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Add Pending JS checks to stock Bootstrap transitions. |
|||
* |
|||
* @module theme_ilb/pending |
|||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk> |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
*/ |
|||
|
|||
import jQuery from 'jquery'; |
|||
const moduleTransitions = { |
|||
alert: [ |
|||
// Alert.
|
|||
{ |
|||
start: 'close', |
|||
end: 'closed', |
|||
}, |
|||
], |
|||
|
|||
carousel: [ |
|||
{ |
|||
start: 'slide', |
|||
end: 'slid', |
|||
}, |
|||
], |
|||
|
|||
collapse: [ |
|||
{ |
|||
start: 'hide', |
|||
end: 'hidden', |
|||
}, |
|||
{ |
|||
start: 'show', |
|||
end: 'shown', |
|||
}, |
|||
], |
|||
|
|||
dropdown: [ |
|||
{ |
|||
start: 'hide', |
|||
end: 'hidden', |
|||
}, |
|||
{ |
|||
start: 'show', |
|||
end: 'shown', |
|||
}, |
|||
], |
|||
|
|||
modal: [ |
|||
{ |
|||
start: 'hide', |
|||
end: 'hidden', |
|||
}, |
|||
{ |
|||
start: 'show', |
|||
end: 'shown', |
|||
}, |
|||
], |
|||
|
|||
popover: [ |
|||
{ |
|||
start: 'hide', |
|||
end: 'hidden', |
|||
}, |
|||
{ |
|||
start: 'show', |
|||
end: 'shown', |
|||
}, |
|||
], |
|||
|
|||
tab: [ |
|||
{ |
|||
start: 'hide', |
|||
end: 'hidden', |
|||
}, |
|||
{ |
|||
start: 'show', |
|||
end: 'shown', |
|||
}, |
|||
], |
|||
|
|||
toast: [ |
|||
{ |
|||
start: 'hide', |
|||
end: 'hidden', |
|||
}, |
|||
{ |
|||
start: 'show', |
|||
end: 'shown', |
|||
}, |
|||
], |
|||
|
|||
tooltip: [ |
|||
{ |
|||
start: 'hide', |
|||
end: 'hidden', |
|||
}, |
|||
{ |
|||
start: 'show', |
|||
end: 'shown', |
|||
}, |
|||
], |
|||
}; |
|||
|
|||
export default () => { |
|||
Object.entries(moduleTransitions).forEach(([key, pairs]) => { |
|||
pairs.forEach(pair => { |
|||
const eventStart = `${pair.start}.bs.${key}`; |
|||
const eventEnd = `${pair.end}.bs.${key}`; |
|||
jQuery(document.body).on(eventStart, e => { |
|||
M.util.js_pending(eventEnd); |
|||
jQuery(e.target).one(eventEnd, () => { |
|||
M.util.js_complete(eventEnd); |
|||
}); |
|||
}); |
|||
|
|||
}); |
|||
}); |
|||
}; |
@ -0,0 +1,28 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Backward compatibility file for the old popover.js |
|||
* |
|||
* @module theme_ilb/popover |
|||
* @copyright 2020 Bas Brands <bas@moodle.com> |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
*/ |
|||
|
|||
import Popover from './bootstrap/popover'; |
|||
|
|||
export { |
|||
Popover |
|||
}; |
@ -0,0 +1,72 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Manage user scroll in Moodle for future floating elements. |
|||
* |
|||
* @module theme_ilb/scroll |
|||
* @copyright 2020 Ferran Recio <ferran@moodle.org> |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
*/ |
|||
|
|||
/** |
|||
* Moodle scroll handling. For now it just handle a "scrolled" class |
|||
* on the body tag but in the near future could handle more floating |
|||
* elements like option bars, docked elements or other active elements. |
|||
* |
|||
* @class theme_ilb/scroll |
|||
*/ |
|||
export default class MoodleScroll { |
|||
|
|||
/** |
|||
* Initialise the scroll monitoring. |
|||
* |
|||
* @method init |
|||
* @chainable |
|||
* @return {Object} this. |
|||
*/ |
|||
init() { |
|||
this.scrollY = 0; |
|||
window.addEventListener("scroll", this.scrollHandler.bind(this)); |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Add special classes to body depending on scroll position. |
|||
* |
|||
* @method update |
|||
* @chainable |
|||
* @return {Integer} current scroll position. |
|||
*/ |
|||
getScrollPosition() { |
|||
return window.pageYOffset || document.documentElement.scrollTop; |
|||
} |
|||
|
|||
/** |
|||
* Add special classes to body depending on scroll position. |
|||
* |
|||
* @method update |
|||
* @chainable |
|||
*/ |
|||
scrollHandler() { |
|||
const body = document.querySelector('body'); |
|||
const scrollY = this.getScrollPosition(); |
|||
if (scrollY >= window.innerHeight) { |
|||
body.classList.add('scrolled'); |
|||
} else { |
|||
body.classList.remove('scrolled'); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
// This file is part of Moodle - http://moodle.org/
|
|||
//
|
|||
// Moodle is free software: you can redistribute it and/or modify
|
|||
// it under the terms of the GNU General Public License as published by
|
|||
// the Free Software Foundation, either version 3 of the License, or
|
|||
// (at your option) any later version.
|
|||
//
|
|||
// Moodle is distributed in the hope that it will be useful,
|
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
// GNU General Public License for more details.
|
|||
//
|
|||
// You should have received a copy of the GNU General Public License
|
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
|||
/** |
|||
* Backward compatibility file for the old toast.js |
|||
* |
|||
* @module theme_ilb/toast |
|||
* @copyright 2020 Bas Brands <bas@moodle.com> |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|||
*/ |
|||
|
|||
import Toast from './bootstrap/toast'; |
|||
|
|||
export { |
|||
Toast |
|||
}; |
@ -0,0 +1,106 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Used to convert a bootswatch file from https://bootswatch.com/ to a Moodle preset. |
|||
* |
|||
* @package theme_ilb |
|||
* @subpackage cli |
|||
* @copyright 2016 Damyon Wiese |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
define('CLI_SCRIPT', true); |
|||
|
|||
require(__DIR__.'/../../../config.php'); |
|||
require_once($CFG->libdir.'/clilib.php'); |
|||
|
|||
$usage = " |
|||
Utility to convert a Bootswatch theme to a Moodle preset compatible with Bootstrap 4. |
|||
|
|||
Download _variables.scss and _bootswatch.scss files from https://bootswatch.com/ |
|||
Run this script. It will generate a new file 'preset.scss' which can be used as |
|||
a Moodle preset. |
|||
|
|||
Usage: |
|||
# php import-bootswatch.php [--help|-h] |
|||
# php import-bootswatch.php --variables=<path> --bootswatch=<path> --preset=<path> |
|||
|
|||
Options: |
|||
-h --help Print this help. |
|||
--variables=<path> Path to the input variables file, defaults to _variables.scss |
|||
--bootswatch=<path> Path to the input bootswatch file, defauls to _bootswatch.scss |
|||
--preset=<path> Path to the output preset file, defaults to preset.scss |
|||
"; |
|||
|
|||
list($options, $unrecognised) = cli_get_params([ |
|||
'help' => false, |
|||
'variables' => '_variables.scss', |
|||
'bootswatch' => '_bootswatch.scss', |
|||
'preset' => 'preset.scss', |
|||
], [ |
|||
'h' => 'help', |
|||
]); |
|||
|
|||
if ($unrecognised) { |
|||
$unrecognised = implode(PHP_EOL.' ', $unrecognised); |
|||
cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised)); |
|||
} |
|||
|
|||
if ($options['help']) { |
|||
cli_writeln($usage); |
|||
exit(2); |
|||
} |
|||
|
|||
if (is_readable($options['variables'])) { |
|||
$sourcevariables = file_get_contents($options['variables']); |
|||
} else { |
|||
cli_writeln($usage); |
|||
cli_error('Error reading the variables file: '.$options['variables']); |
|||
} |
|||
|
|||
|
|||
if (is_readable($options['bootswatch'])) { |
|||
$sourcebootswatch = file_get_contents($options['bootswatch']); |
|||
} else { |
|||
cli_writeln($usage); |
|||
cli_error('Error reading the bootswatch file: '.$options['bootswatch']); |
|||
} |
|||
|
|||
// Write the preset file. |
|||
$out = fopen($options['preset'], 'w'); |
|||
|
|||
if (!$out) { |
|||
cli_error('Error writing to the preset file'); |
|||
} |
|||
|
|||
fwrite($out, $sourcevariables); |
|||
|
|||
fwrite($out, ' |
|||
// Import FontAwesome. |
|||
@import "fontawesome"; |
|||
|
|||
// Import All of Bootstrap |
|||
@import "bootstrap"; |
|||
|
|||
// Import Core moodle CSS |
|||
@import "moodle"; |
|||
'); |
|||
|
|||
// Add the bootswatch file. |
|||
fwrite($out, $sourcebootswatch); |
|||
|
|||
fclose($out); |
@ -0,0 +1,53 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Language file. |
|||
* |
|||
* @package theme_ilb |
|||
* @copyright 2016 Frédéric Massart |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
$string['advancedsettings'] = 'Advanced settings'; |
|||
$string['backgroundimage'] = 'Background image'; |
|||
$string['backgroundimage_desc'] = 'The image to display as a background of the site. The background image you upload here will override the background image in your theme preset files.'; |
|||
$string['brandcolor'] = 'Brand colour'; |
|||
$string['brandcolor_desc'] = 'The accent colour.'; |
|||
$string['bootswatch'] = 'Bootswatch'; |
|||
$string['bootswatch_desc'] = 'A bootswatch is a set of Bootstrap variables and css to style Bootstrap'; |
|||
$string['choosereadme'] = 'Ilb is a modern highly-customisable theme. This theme is intended to be used directly, or as a parent theme when creating new themes utilising Bootstrap 4.'; |
|||
$string['currentinparentheses'] = '(current)'; |
|||
$string['configtitle'] = 'Ilb'; |
|||
$string['generalsettings'] = 'General settings'; |
|||
$string['nobootswatch'] = 'None'; |
|||
$string['pluginname'] = 'Ilb'; |
|||
$string['presetfiles'] = 'Additional theme preset files'; |
|||
$string['presetfiles_desc'] = 'Preset files can be used to dramatically alter the appearance of the theme. See <a href="https://docs.moodle.org/dev/Ilb_Presets">Ilb presets</a> for information on creating and sharing your own preset files, and see the <a href="https://archive.moodle.net/ilb">Presets repository</a> for presets that others have shared.'; |
|||
$string['preset'] = 'Theme preset'; |
|||
$string['preset_desc'] = 'Pick a preset to broadly change the look of the theme.'; |
|||
$string['privacy:metadata'] = 'The Ilb theme does not store any personal data about any user.'; |
|||
$string['rawscss'] = 'Raw SCSS'; |
|||
$string['rawscss_desc'] = 'Use this field to provide SCSS or CSS code which will be injected at the end of the style sheet.'; |
|||
$string['rawscsspre'] = 'Raw initial SCSS'; |
|||
$string['rawscsspre_desc'] = 'In this field you can provide initialising SCSS code, it will be injected before everything else. Most of the time you will use this setting to define variables.'; |
|||
$string['region-side-pre'] = 'Right'; |
|||
$string['privacy:metadata:preference:draweropennav'] = 'The user\'s preference for hiding or showing the drawer menu navigation.'; |
|||
$string['privacy:drawernavclosed'] = 'The current preference for the navigation drawer is closed.'; |
|||
$string['privacy:drawernavopen'] = 'The current preference for the navigation drawer is open.'; |
|||
$string['totop'] = 'Go to top'; |
@ -0,0 +1,62 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* A two column layout for the ilb theme. |
|||
* |
|||
* @package theme_ilb |
|||
* @copyright 2016 Damyon Wiese |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
user_preference_allow_ajax_update('drawer-open-nav', PARAM_ALPHA); |
|||
require_once($CFG->libdir . '/behat/lib.php'); |
|||
|
|||
if (isloggedin()) { |
|||
$navdraweropen = (get_user_preferences('drawer-open-nav', 'true') == 'true'); |
|||
} else { |
|||
$navdraweropen = false; |
|||
} |
|||
|
|||
|
|||
$extraclasses = []; |
|||
if ($navdraweropen) { |
|||
$extraclasses[] = 'drawer-open-left'; |
|||
} |
|||
$bodyattributes = $OUTPUT->body_attributes($extraclasses); |
|||
$blockshtml = $OUTPUT->blocks('side-pre'); |
|||
$hasblocks = strpos($blockshtml, 'data-block=') !== false; |
|||
$buildregionmainsettings = !$PAGE->include_region_main_settings_in_header_actions(); |
|||
// If the settings menu will be included in the header then don't add it here. |
|||
$regionmainsettingsmenu = $buildregionmainsettings ? $OUTPUT->region_main_settings_menu() : false; |
|||
$templatecontext = [ |
|||
'sitename' => format_string($SITE->shortname, true, ['context' => context_course::instance(SITEID), "escape" => false]), |
|||
'output' => $OUTPUT, |
|||
'sidepreblocks' => $blockshtml, |
|||
'hasblocks' => $hasblocks, |
|||
'bodyattributes' => $bodyattributes, |
|||
'navdraweropen' => $navdraweropen, |
|||
'regionmainsettingsmenu' => $regionmainsettingsmenu, |
|||
'hasregionmainsettingsmenu' => !empty($regionmainsettingsmenu) |
|||
]; |
|||
|
|||
$nav = $PAGE->flatnav; |
|||
$templatecontext['flatnavigation'] = $nav; |
|||
$templatecontext['firstcollectionlabel'] = $nav->get_collectionlabel(); |
|||
echo $OUTPUT->render_from_template('theme_ilb/frontpage', $templatecontext); |
|||
|
After Width: | Height: | Size: 135 KiB |
@ -0,0 +1,36 @@ |
|||
Description of Twitter bootstrap import into Moodle |
|||
|
|||
Twitter bootstrap |
|||
----------------- |
|||
|
|||
Sass: |
|||
This theme uses Bootstrap version 4.6.0 |
|||
The Bootstrap repository is available on: |
|||
|
|||
https://github.com/twitter/bootstrap.git |
|||
|
|||
To update to the latest release of twitter bootstrap: |
|||
|
|||
* download bootstrap to your home folder |
|||
* remove folder theme/ilb/scss/bootstrap |
|||
* copy the scss files from ~/bootstrap/scss to theme/ilb/scss/bootstrap |
|||
* comment out left: 0; from .popover {} in scss/bootstrap/_popover.scss. In RTL mode this prevents popovers from showing and it is not required in LTR mode. |
|||
* comment out this line in theme/ilb/scss/_print.scss |
|||
@page { |
|||
size: $print-page-size; |
|||
} |
|||
It breaks when compiled with phpscss. |
|||
* update ./thirdpartylibs.xml |
|||
|
|||
Javascript: |
|||
|
|||
* remove folder theme/ilb/amd/src/bootstrap |
|||
* copy the js files from ~/bootstrap/js/src to theme/ilb/amd/src/bootstrap (including the subfolder) |
|||
* copy index.js from ~/bootstrap/js to theme/ilb/amd/src |
|||
* edit theme/ilb/amd/src/index.js and update import path (src -> bootstrap) |
|||
* Moodle core includes the popper.js library, make sure each of the new Bootstrap js files |
|||
includes the 'core/popper' library instead of 'popper.js'. For version 4.6.0 these files were: tooltip.js and dropdown.js |
|||
* update ./thirdpartylibs.xml to include all new Bootstrap js files |
|||
* run "grunt ignorefiles" to prevent linting errors appearing from the new Bootstrap js files. |
|||
* in folder theme/ilb run "grunt amd" to compile the bootstrap JS |
|||
* in folder theme/ilb run "grunt css" to compile scss |
@ -0,0 +1,2 @@ |
|||
// Import Bootstrap. |
|||
@import "bootstrap/bootstrap"; |
@ -0,0 +1,54 @@ |
|||
// Base class |
|||
// |
|||
// Requires one of the contextual, color modifier classes for `color` and |
|||
// `background-color`. |
|||
|
|||
.badge { |
|||
display: inline-block; |
|||
padding: $badge-padding-y $badge-padding-x; |
|||
@include font-size($badge-font-size); |
|||
font-weight: $badge-font-weight; |
|||
line-height: 1; |
|||
text-align: center; |
|||
white-space: nowrap; |
|||
vertical-align: baseline; |
|||
@include border-radius($badge-border-radius); |
|||
@include transition($badge-transition); |
|||
|
|||
@at-root a#{&} { |
|||
@include hover-focus() { |
|||
text-decoration: none; |
|||
} |
|||
} |
|||
|
|||
// Empty badges collapse automatically |
|||
&:empty { |
|||
display: none; |
|||
} |
|||
} |
|||
|
|||
// Quick fix for badges in buttons |
|||
.btn .badge { |
|||
position: relative; |
|||
top: -1px; |
|||
} |
|||
|
|||
// Pill badges |
|||
// |
|||
// Make them extra rounded with a modifier to replace v3's badges. |
|||
|
|||
.badge-pill { |
|||
padding-right: $badge-pill-padding-x; |
|||
padding-left: $badge-pill-padding-x; |
|||
@include border-radius($badge-pill-border-radius); |
|||
} |
|||
|
|||
// Colors |
|||
// |
|||
// Contextual variations (linked badges get darker on :hover). |
|||
|
|||
@each $color, $value in $theme-colors { |
|||
.badge-#{$color} { |
|||
@include badge-variant($value); |
|||
} |
|||
} |
@ -0,0 +1,144 @@ |
|||
// Bootstrap functions |
|||
// |
|||
// Utility mixins and functions for evaluating source code across our variables, maps, and mixins. |
|||
|
|||
// Ascending |
|||
// Used to evaluate Sass maps like our grid breakpoints. |
|||
@mixin _assert-ascending($map, $map-name) { |
|||
$prev-key: null; |
|||
$prev-num: null; |
|||
@each $key, $num in $map { |
|||
@if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" { |
|||
// Do nothing |
|||
} @else if not comparable($prev-num, $num) { |
|||
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; |
|||
} @else if $prev-num >= $num { |
|||
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; |
|||
} |
|||
$prev-key: $key; |
|||
$prev-num: $num; |
|||
} |
|||
} |
|||
|
|||
// Starts at zero |
|||
// Used to ensure the min-width of the lowest breakpoint starts at 0. |
|||
@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") { |
|||
@if length($map) > 0 { |
|||
$values: map-values($map); |
|||
$first-value: nth($values, 1); |
|||
@if $first-value != 0 { |
|||
@warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}."; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Replace `$search` with `$replace` in `$string` |
|||
// Used on our SVG icon backgrounds for custom forms. |
|||
// |
|||
// @author Hugo Giraudel |
|||
// @param {String} $string - Initial string |
|||
// @param {String} $search - Substring to replace |
|||
// @param {String} $replace ('') - New value |
|||
// @return {String} - Updated string |
|||
@function str-replace($string, $search, $replace: "") { |
|||
$index: str-index($string, $search); |
|||
|
|||
@if $index { |
|||
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); |
|||
} |
|||
|
|||
@return $string; |
|||
} |
|||
|
|||
// See https://codepen.io/kevinweber/pen/dXWoRw |
|||
// |
|||
// Requires the use of quotes around data URIs. |
|||
|
|||
@function escape-svg($string) { |
|||
@if str-index($string, "data:image/svg+xml") { |
|||
@each $char, $encoded in $escaped-characters { |
|||
// Do not escape the url brackets |
|||
@if str-index($string, "url(") == 1 { |
|||
$string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}"); |
|||
} @else { |
|||
$string: str-replace($string, $char, $encoded); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@return $string; |
|||
} |
|||
|
|||
// Color contrast |
|||
@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) { |
|||
$r: red($color); |
|||
$g: green($color); |
|||
$b: blue($color); |
|||
|
|||
$yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000; |
|||
|
|||
@if ($yiq >= $yiq-contrasted-threshold) { |
|||
@return $dark; |
|||
} @else { |
|||
@return $light; |
|||
} |
|||
} |
|||
|
|||
// Retrieve color Sass maps |
|||
@function color($key: "blue") { |
|||
@return map-get($colors, $key); |
|||
} |
|||
|
|||
@function theme-color($key: "primary") { |
|||
@return map-get($theme-colors, $key); |
|||
} |
|||
|
|||
@function gray($key: "100") { |
|||
@return map-get($grays, $key); |
|||
} |
|||
|
|||
// Request a theme color level |
|||
@function theme-color-level($color-name: "primary", $level: 0) { |
|||
$color: theme-color($color-name); |
|||
$color-base: if($level > 0, $black, $white); |
|||
$level: abs($level); |
|||
|
|||
@return mix($color-base, $color, $level * $theme-color-interval); |
|||
} |
|||
|
|||
// Return valid calc |
|||
@function add($value1, $value2, $return-calc: true) { |
|||
@if $value1 == null { |
|||
@return $value2; |
|||
} |
|||
|
|||
@if $value2 == null { |
|||
@return $value1; |
|||
} |
|||
|
|||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { |
|||
@return $value1 + $value2; |
|||
} |
|||
|
|||
@return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2); |
|||
} |
|||
|
|||
@function subtract($value1, $value2, $return-calc: true) { |
|||
@if $value1 == null and $value2 == null { |
|||
@return null; |
|||
} |
|||
|
|||
@if $value1 == null { |
|||
@return -$value2; |
|||
} |
|||
|
|||
@if $value2 == null { |
|||
@return $value1; |
|||
} |
|||
|
|||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { |
|||
@return $value1 - $value2; |
|||
} |
|||
|
|||
@return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2); |
|||
} |
@ -0,0 +1,19 @@ |
|||
:root { |
|||
// Custom variable values only support SassScript inside `#{}`. |
|||
@each $color, $value in $colors { |
|||
--#{$color}: #{$value}; |
|||
} |
|||
|
|||
@each $color, $value in $theme-colors { |
|||
--#{$color}: #{$value}; |
|||
} |
|||
|
|||
@each $bp, $value in $grid-breakpoints { |
|||
--breakpoint-#{$bp}: #{$value}; |
|||
} |
|||
|
|||
// Use `inspect` for lists so that quoted items keep the quotes. |
|||
// See https://github.com/sass/sass/issues/2383#issuecomment-336349172 |
|||
--font-family-sans-serif: #{inspect($font-family-sans-serif)}; |
|||
--font-family-monospace: #{inspect($font-family-monospace)}; |
|||
} |
@ -0,0 +1,65 @@ |
|||
// |
|||
// Rotating border |
|||
// |
|||
|
|||
@keyframes spinner-border { |
|||
to { transform: rotate(360deg); } |
|||
} |
|||
|
|||
.spinner-border { |
|||
display: inline-block; |
|||
width: $spinner-width; |
|||
height: $spinner-height; |
|||
vertical-align: text-bottom; |
|||
border: $spinner-border-width solid currentColor; |
|||
border-right-color: transparent; |
|||
// stylelint-disable-next-line property-disallowed-list |
|||
border-radius: 50%; |
|||
animation: .75s linear infinite spinner-border; |
|||
} |
|||
|
|||
.spinner-border-sm { |
|||
width: $spinner-width-sm; |
|||
height: $spinner-height-sm; |
|||
border-width: $spinner-border-width-sm; |
|||
} |
|||
|
|||
// |
|||
// Growing circle |
|||
// |
|||
|
|||
@keyframes spinner-grow { |
|||
0% { |
|||
transform: scale(0); |
|||
} |
|||
50% { |
|||
opacity: 1; |
|||
transform: none; |
|||
} |
|||
} |
|||
|
|||
.spinner-grow { |
|||
display: inline-block; |
|||
width: $spinner-width; |
|||
height: $spinner-height; |
|||
vertical-align: text-bottom; |
|||
background-color: currentColor; |
|||
// stylelint-disable-next-line property-disallowed-list |
|||
border-radius: 50%; |
|||
opacity: 0; |
|||
animation: .75s linear infinite spinner-grow; |
|||
} |
|||
|
|||
.spinner-grow-sm { |
|||
width: $spinner-width-sm; |
|||
height: $spinner-height-sm; |
|||
} |
|||
|
|||
@if $enable-prefers-reduced-motion-media-query { |
|||
@media (prefers-reduced-motion: reduce) { |
|||
.spinner-border, |
|||
.spinner-grow { |
|||
animation-duration: 1.5s; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
.toast { |
|||
// Prevents from shrinking in IE11, when in a flex container |
|||
// See https://github.com/twbs/bootstrap/issues/28341 |
|||
flex-basis: $toast-max-width; |
|||
max-width: $toast-max-width; |
|||
@include font-size($toast-font-size); |
|||
color: $toast-color; |
|||
background-color: $toast-background-color; |
|||
background-clip: padding-box; |
|||
border: $toast-border-width solid $toast-border-color; |
|||
box-shadow: $toast-box-shadow; |
|||
opacity: 0; |
|||
@include border-radius($toast-border-radius); |
|||
|
|||
&:not(:last-child) { |
|||
margin-bottom: $toast-padding-x; |
|||
} |
|||
|
|||
&.showing { |
|||
opacity: 1; |
|||
} |
|||
|
|||
&.show { |
|||
display: block; |
|||
opacity: 1; |
|||
} |
|||
|
|||
&.hide { |
|||
display: none; |
|||
} |
|||
} |
|||
|
|||
.toast-header { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: $toast-padding-y $toast-padding-x; |
|||
color: $toast-header-color; |
|||
background-color: $toast-header-background-color; |
|||
background-clip: padding-box; |
|||
border-bottom: $toast-border-width solid $toast-header-border-color; |
|||
@include border-top-radius(subtract($toast-border-radius, $toast-border-width)); |
|||
} |
|||
|
|||
.toast-body { |
|||
padding: $toast-padding-x; // apply to both vertical and horizontal |
|||
} |
@ -0,0 +1,20 @@ |
|||
.fade { |
|||
@include transition($transition-fade); |
|||
|
|||
&:not(.show) { |
|||
opacity: 0; |
|||
} |
|||
} |
|||
|
|||
.collapse { |
|||
&:not(.show) { |
|||
display: none; |
|||
} |
|||
} |
|||
|
|||
.collapsing { |
|||
position: relative; |
|||
height: 0; |
|||
overflow: hidden; |
|||
@include transition($transition-collapse); |
|||
} |
@ -0,0 +1,17 @@ |
|||
@mixin badge-variant($bg) { |
|||
color: color-yiq($bg); |
|||
background-color: $bg; |
|||
|
|||
@at-root a#{&} { |
|||
@include hover-focus() { |
|||
color: color-yiq($bg); |
|||
background-color: darken($bg, 10%); |
|||
} |
|||
|
|||
&:focus, |
|||
&.focus { |
|||
outline: 0; |
|||
box-shadow: 0 0 0 $badge-focus-width rgba($bg, .5); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
@mixin box-shadow($shadow...) { |
|||
@if $enable-shadows { |
|||
$result: (); |
|||
|
|||
@if (length($shadow) == 1) { |
|||
// We can pass `@include box-shadow(none);` |
|||
$result: $shadow; |
|||
} @else { |
|||
// Filter to avoid invalid properties for example `box-shadow: none, 1px 1px black;` |
|||
@for $i from 1 through length($shadow) { |
|||
@if nth($shadow, $i) != "none" { |
|||
$result: append($result, nth($shadow, $i), "comma"); |
|||
} |
|||
} |
|||
} |
|||
@if (length($result) > 0) { |
|||
box-shadow: $result; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,62 @@ |
|||
@mixin caret-down() { |
|||
border-top: $caret-width solid; |
|||
border-right: $caret-width solid transparent; |
|||
border-bottom: 0; |
|||
border-left: $caret-width solid transparent; |
|||
} |
|||
|
|||
@mixin caret-up() { |
|||
border-top: 0; |
|||
border-right: $caret-width solid transparent; |
|||
border-bottom: $caret-width solid; |
|||
border-left: $caret-width solid transparent; |
|||
} |
|||
|
|||
@mixin caret-right() { |
|||
border-top: $caret-width solid transparent; |
|||
border-right: 0; |
|||
border-bottom: $caret-width solid transparent; |
|||
border-left: $caret-width solid; |
|||
} |
|||
|
|||
@mixin caret-left() { |
|||
border-top: $caret-width solid transparent; |
|||
border-right: $caret-width solid; |
|||
border-bottom: $caret-width solid transparent; |
|||
} |
|||
|
|||
@mixin caret($direction: down) { |
|||
@if $enable-caret { |
|||
&::after { |
|||
display: inline-block; |
|||
margin-left: $caret-spacing; |
|||
vertical-align: $caret-vertical-align; |
|||
content: ""; |
|||
@if $direction == down { |
|||
@include caret-down(); |
|||
} @else if $direction == up { |
|||
@include caret-up(); |
|||
} @else if $direction == right { |
|||
@include caret-right(); |
|||
} |
|||
} |
|||
|
|||
@if $direction == left { |
|||
&::after { |
|||
display: none; |
|||
} |
|||
|
|||
&::before { |
|||
display: inline-block; |
|||
margin-right: $caret-spacing; |
|||
vertical-align: $caret-vertical-align; |
|||
content: ""; |
|||
@include caret-left(); |
|||
} |
|||
} |
|||
|
|||
&:empty::after { |
|||
margin-left: 0; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
// Deprecate mixin |
|||
// |
|||
// This mixin can be used to deprecate mixins or functions. |
|||
// `$enable-deprecation-messages` is a global variable, `$ignore-warning` is a variable that can be passed to |
|||
// some deprecated mixins to suppress the warning (for example if the mixin is still be used in the current version of Bootstrap) |
|||
@mixin deprecate($name, $deprecate-version, $remove-version, $ignore-warning: false) { |
|||
@if ($enable-deprecation-messages != false and $ignore-warning != true) { |
|||
@warn "#{$name} has been deprecated as of #{$deprecate-version}. It will be removed entirely in #{$remove-version}."; |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
@mixin float-left() { |
|||
float: left !important; |
|||
@include deprecate("The `float-left` mixin", "v4.3.0", "v5"); |
|||
} |
|||
@mixin float-right() { |
|||
float: right !important; |
|||
@include deprecate("The `float-right` mixin", "v4.3.0", "v5"); |
|||
} |
|||
@mixin float-none() { |
|||
float: none !important; |
|||
@include deprecate("The `float-none` mixin", "v4.3.0", "v5"); |
|||
} |
@ -0,0 +1,26 @@ |
|||
// stylelint-disable property-disallowed-list |
|||
@mixin transition($transition...) { |
|||
@if length($transition) == 0 { |
|||
$transition: $transition-base; |
|||
} |
|||
|
|||
@if length($transition) > 1 { |
|||
@each $value in $transition { |
|||
@if $value == null or $value == none { |
|||
@warn "The keyword 'none' or 'null' must be used as a single argument."; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@if $enable-transitions { |
|||
@if nth($transition, 1) != null { |
|||
transition: $transition; |
|||
} |
|||
|
|||
@if $enable-prefers-reduced-motion-media-query and nth($transition, 1) != null and nth($transition, 1) != none { |
|||
@media (prefers-reduced-motion: reduce) { |
|||
transition: none; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,8 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
// Visibility |
|||
|
|||
@mixin invisible($visibility) { |
|||
visibility: $visibility !important; |
|||
@include deprecate("`invisible()`", "v4.3.0", "v5"); |
|||
} |
@ -0,0 +1,8 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
.align-baseline { vertical-align: baseline !important; } // Browser default |
|||
.align-top { vertical-align: top !important; } |
|||
.align-middle { vertical-align: middle !important; } |
|||
.align-bottom { vertical-align: bottom !important; } |
|||
.align-text-bottom { vertical-align: text-bottom !important; } |
|||
.align-text-top { vertical-align: text-top !important; } |
@ -0,0 +1,75 @@ |
|||
// stylelint-disable property-disallowed-list, declaration-no-important |
|||
|
|||
// |
|||
// Border |
|||
// |
|||
|
|||
.border { border: $border-width solid $border-color !important; } |
|||
.border-top { border-top: $border-width solid $border-color !important; } |
|||
.border-right { border-right: $border-width solid $border-color !important; } |
|||
.border-bottom { border-bottom: $border-width solid $border-color !important; } |
|||
.border-left { border-left: $border-width solid $border-color !important; } |
|||
|
|||
.border-0 { border: 0 !important; } |
|||
.border-top-0 { border-top: 0 !important; } |
|||
.border-right-0 { border-right: 0 !important; } |
|||
.border-bottom-0 { border-bottom: 0 !important; } |
|||
.border-left-0 { border-left: 0 !important; } |
|||
|
|||
@each $color, $value in $theme-colors { |
|||
.border-#{$color} { |
|||
border-color: $value !important; |
|||
} |
|||
} |
|||
|
|||
.border-white { |
|||
border-color: $white !important; |
|||
} |
|||
|
|||
// |
|||
// Border-radius |
|||
// |
|||
|
|||
.rounded-sm { |
|||
border-radius: $border-radius-sm !important; |
|||
} |
|||
|
|||
.rounded { |
|||
border-radius: $border-radius !important; |
|||
} |
|||
|
|||
.rounded-top { |
|||
border-top-left-radius: $border-radius !important; |
|||
border-top-right-radius: $border-radius !important; |
|||
} |
|||
|
|||
.rounded-right { |
|||
border-top-right-radius: $border-radius !important; |
|||
border-bottom-right-radius: $border-radius !important; |
|||
} |
|||
|
|||
.rounded-bottom { |
|||
border-bottom-right-radius: $border-radius !important; |
|||
border-bottom-left-radius: $border-radius !important; |
|||
} |
|||
|
|||
.rounded-left { |
|||
border-top-left-radius: $border-radius !important; |
|||
border-bottom-left-radius: $border-radius !important; |
|||
} |
|||
|
|||
.rounded-lg { |
|||
border-radius: $border-radius-lg !important; |
|||
} |
|||
|
|||
.rounded-circle { |
|||
border-radius: 50% !important; |
|||
} |
|||
|
|||
.rounded-pill { |
|||
border-radius: $rounded-pill !important; |
|||
} |
|||
|
|||
.rounded-0 { |
|||
border-radius: 0 !important; |
|||
} |
@ -0,0 +1,39 @@ |
|||
// Credit: Nicolas Gallagher and SUIT CSS. |
|||
|
|||
.embed-responsive { |
|||
position: relative; |
|||
display: block; |
|||
width: 100%; |
|||
padding: 0; |
|||
overflow: hidden; |
|||
|
|||
&::before { |
|||
display: block; |
|||
content: ""; |
|||
} |
|||
|
|||
.embed-responsive-item, |
|||
iframe, |
|||
embed, |
|||
object, |
|||
video { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
border: 0; |
|||
} |
|||
} |
|||
|
|||
@each $embed-responsive-aspect-ratio in $embed-responsive-aspect-ratios { |
|||
$embed-responsive-aspect-ratio-x: nth($embed-responsive-aspect-ratio, 1); |
|||
$embed-responsive-aspect-ratio-y: nth($embed-responsive-aspect-ratio, 2); |
|||
|
|||
.embed-responsive-#{$embed-responsive-aspect-ratio-x}by#{$embed-responsive-aspect-ratio-y} { |
|||
&::before { |
|||
padding-top: percentage($embed-responsive-aspect-ratio-y / $embed-responsive-aspect-ratio-x); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
@each $breakpoint in map-keys($grid-breakpoints) { |
|||
@include media-breakpoint-up($breakpoint) { |
|||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints); |
|||
|
|||
.float#{$infix}-left { float: left !important; } |
|||
.float#{$infix}-right { float: right !important; } |
|||
.float#{$infix}-none { float: none !important; } |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
@each $value in $user-selects { |
|||
.user-select-#{$value} { user-select: $value !important; } |
|||
} |
@ -0,0 +1,5 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
@each $value in $overflows { |
|||
.overflow-#{$value} { overflow: $value !important; } |
|||
} |
@ -0,0 +1,32 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
// Common values |
|||
@each $position in $positions { |
|||
.position-#{$position} { position: $position !important; } |
|||
} |
|||
|
|||
// Shorthand |
|||
|
|||
.fixed-top { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
left: 0; |
|||
z-index: $zindex-fixed; |
|||
} |
|||
|
|||
.fixed-bottom { |
|||
position: fixed; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: $zindex-fixed; |
|||
} |
|||
|
|||
.sticky-top { |
|||
@supports (position: sticky) { |
|||
position: sticky; |
|||
top: 0; |
|||
z-index: $zindex-sticky; |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
.shadow-sm { box-shadow: $box-shadow-sm !important; } |
|||
.shadow { box-shadow: $box-shadow !important; } |
|||
.shadow-lg { box-shadow: $box-shadow-lg !important; } |
|||
.shadow-none { box-shadow: none !important; } |
@ -0,0 +1,20 @@ |
|||
// stylelint-disable declaration-no-important |
|||
|
|||
// Width and height |
|||
|
|||
@each $prop, $abbrev in (width: w, height: h) { |
|||
@each $size, $length in $sizes { |
|||
.#{$abbrev}-#{$size} { #{$prop}: $length !important; } |
|||
} |
|||
} |
|||
|
|||
.mw-100 { max-width: 100% !important; } |
|||
.mh-100 { max-height: 100% !important; } |
|||
|
|||
// Viewport additional helpers |
|||
|
|||
.min-vw-100 { min-width: 100vw !important; } |
|||
.min-vh-100 { min-height: 100vh !important; } |
|||
|
|||
.vw-100 { width: 100vw !important; } |
|||
.vh-100 { height: 100vh !important; } |
@ -0,0 +1,19 @@ |
|||
// |
|||
// Stretched link |
|||
// |
|||
|
|||
.stretched-link { |
|||
&::after { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 1; |
|||
// Just in case `pointer-events: none` is set on a parent |
|||
pointer-events: auto; |
|||
content: ""; |
|||
// IE10 bugfix, see https://stackoverflow.com/questions/16947967/ie10-hover-pseudo-class-doesnt-work-without-background-color |
|||
background-color: rgba(0, 0, 0, 0); |
|||
} |
|||
} |
@ -0,0 +1,204 @@ |
|||
// stylelint-disable property-blacklist, scss/dollar-variable-default |
|||
|
|||
// SCSS RFS mixin |
|||
// |
|||
// Automated font-resizing |
|||
// |
|||
// See https://github.com/twbs/rfs |
|||
|
|||
// Configuration |
|||
|
|||
// Base font size |
|||
$rfs-base-font-size: 1.25rem !default; |
|||
$rfs-font-size-unit: rem !default; |
|||
|
|||
// Breakpoint at where font-size starts decreasing if screen width is smaller |
|||
$rfs-breakpoint: 1200px !default; |
|||
$rfs-breakpoint-unit: px !default; |
|||
|
|||
// Resize font-size based on screen height and width |
|||
$rfs-two-dimensional: false !default; |
|||
|
|||
// Factor of decrease |
|||
$rfs-factor: 10 !default; |
|||
|
|||
@if type-of($rfs-factor) != "number" or $rfs-factor <= 1 { |
|||
@error "`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1."; |
|||
} |
|||
|
|||
// Generate enable or disable classes. Possibilities: false, "enable" or "disable" |
|||
$rfs-class: false !default; |
|||
|
|||
// 1 rem = $rfs-rem-value px |
|||
$rfs-rem-value: 16 !default; |
|||
|
|||
// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14 |
|||
$rfs-safari-iframe-resize-bug-fix: false !default; |
|||
|
|||
// Disable RFS by setting $enable-responsive-font-sizes to false |
|||
$enable-responsive-font-sizes: true !default; |
|||
|
|||
// Cache $rfs-base-font-size unit |
|||
$rfs-base-font-size-unit: unit($rfs-base-font-size); |
|||
|
|||
// Remove px-unit from $rfs-base-font-size for calculations |
|||
@if $rfs-base-font-size-unit == "px" { |
|||
$rfs-base-font-size: $rfs-base-font-size / ($rfs-base-font-size * 0 + 1); |
|||
} |
|||
@else if $rfs-base-font-size-unit == "rem" { |
|||
$rfs-base-font-size: $rfs-base-font-size / ($rfs-base-font-size * 0 + 1 / $rfs-rem-value); |
|||
} |
|||
|
|||
// Cache $rfs-breakpoint unit to prevent multiple calls |
|||
$rfs-breakpoint-unit-cache: unit($rfs-breakpoint); |
|||
|
|||
// Remove unit from $rfs-breakpoint for calculations |
|||
@if $rfs-breakpoint-unit-cache == "px" { |
|||
$rfs-breakpoint: $rfs-breakpoint / ($rfs-breakpoint * 0 + 1); |
|||
} |
|||
@else if $rfs-breakpoint-unit-cache == "rem" or $rfs-breakpoint-unit-cache == "em" { |
|||
$rfs-breakpoint: $rfs-breakpoint / ($rfs-breakpoint * 0 + 1 / $rfs-rem-value); |
|||
} |
|||
|
|||
// Responsive font-size mixin |
|||
@mixin rfs($fs, $important: false) { |
|||
// Cache $fs unit |
|||
$fs-unit: if(type-of($fs) == "number", unit($fs), false); |
|||
|
|||
// Add !important suffix if needed |
|||
$rfs-suffix: if($important, " !important", ""); |
|||
|
|||
// If $fs isn't a number (like inherit) or $fs has a unit (not px or rem, like 1.5em) or $ is 0, just print the value |
|||
@if not $fs-unit or $fs-unit != "" and $fs-unit != "px" and $fs-unit != "rem" or $fs == 0 { |
|||
font-size: #{$fs}#{$rfs-suffix}; |
|||
} |
|||
@else { |
|||
// Variables for storing static and fluid rescaling |
|||
$rfs-static: null; |
|||
$rfs-fluid: null; |
|||
|
|||
// Remove px-unit from $fs for calculations |
|||
@if $fs-unit == "px" { |
|||
$fs: $fs / ($fs * 0 + 1); |
|||
} |
|||
@else if $fs-unit == "rem" { |
|||
$fs: $fs / ($fs * 0 + 1 / $rfs-rem-value); |
|||
} |
|||
|
|||
// Set default font-size |
|||
@if $rfs-font-size-unit == rem { |
|||
$rfs-static: #{$fs / $rfs-rem-value}rem#{$rfs-suffix}; |
|||
} |
|||
@else if $rfs-font-size-unit == px { |
|||
$rfs-static: #{$fs}px#{$rfs-suffix}; |
|||
} |
|||
@else { |
|||
@error "`#{$rfs-font-size-unit}` is not a valid unit for $rfs-font-size-unit. Use `px` or `rem`."; |
|||
} |
|||
|
|||
// Only add media query if font-size is bigger as the minimum font-size |
|||
// If $rfs-factor == 1, no rescaling will take place |
|||
@if $fs > $rfs-base-font-size and $enable-responsive-font-sizes { |
|||
$min-width: null; |
|||
$variable-unit: null; |
|||
|
|||
// Calculate minimum font-size for given font-size |
|||
$fs-min: $rfs-base-font-size + ($fs - $rfs-base-font-size) / $rfs-factor; |
|||
|
|||
// Calculate difference between given font-size and minimum font-size for given font-size |
|||
$fs-diff: $fs - $fs-min; |
|||
|
|||
// Base font-size formatting |
|||
// No need to check if the unit is valid, because we did that before |
|||
$min-width: if($rfs-font-size-unit == rem, #{$fs-min / $rfs-rem-value}rem, #{$fs-min}px); |
|||
|
|||
// If two-dimensional, use smallest of screen width and height |
|||
$variable-unit: if($rfs-two-dimensional, vmin, vw); |
|||
|
|||
// Calculate the variable width between 0 and $rfs-breakpoint |
|||
$variable-width: #{$fs-diff * 100 / $rfs-breakpoint}#{$variable-unit}; |
|||
|
|||
// Set the calculated font-size. |
|||
$rfs-fluid: calc(#{$min-width} + #{$variable-width}) #{$rfs-suffix}; |
|||
} |
|||
|
|||
// Rendering |
|||
@if $rfs-fluid == null { |
|||
// Only render static font-size if no fluid font-size is available |
|||
font-size: $rfs-static; |
|||
} |
|||
@else { |
|||
$mq-value: null; |
|||
|
|||
// RFS breakpoint formatting |
|||
@if $rfs-breakpoint-unit == em or $rfs-breakpoint-unit == rem { |
|||
$mq-value: #{$rfs-breakpoint / $rfs-rem-value}#{$rfs-breakpoint-unit}; |
|||
} |
|||
@else if $rfs-breakpoint-unit == px { |
|||
$mq-value: #{$rfs-breakpoint}px; |
|||
} |
|||
@else { |
|||
@error "`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`."; |
|||
} |
|||
|
|||
@if $rfs-class == "disable" { |
|||
// Adding an extra class increases specificity, |
|||
// which prevents the media query to override the font size |
|||
&, |
|||
.disable-responsive-font-size &, |
|||
&.disable-responsive-font-size { |
|||
font-size: $rfs-static; |
|||
} |
|||
} |
|||
@else { |
|||
font-size: $rfs-static; |
|||
} |
|||
|
|||
@if $rfs-two-dimensional { |
|||
@media (max-width: #{$mq-value}), (max-height: #{$mq-value}) { |
|||
@if $rfs-class == "enable" { |
|||
.enable-responsive-font-size &, |
|||
&.enable-responsive-font-size { |
|||
font-size: $rfs-fluid; |
|||
} |
|||
} |
|||
@else { |
|||
font-size: $rfs-fluid; |
|||
} |
|||
|
|||
@if $rfs-safari-iframe-resize-bug-fix { |
|||
// stylelint-disable-next-line length-zero-no-unit |
|||
min-width: 0vw; |
|||
} |
|||
} |
|||
} |
|||
@else { |
|||
@media (max-width: #{$mq-value}) { |
|||
@if $rfs-class == "enable" { |
|||
.enable-responsive-font-size &, |
|||
&.enable-responsive-font-size { |
|||
font-size: $rfs-fluid; |
|||
} |
|||
} |
|||
@else { |
|||
font-size: $rfs-fluid; |
|||
} |
|||
|
|||
@if $rfs-safari-iframe-resize-bug-fix { |
|||
// stylelint-disable-next-line length-zero-no-unit |
|||
min-width: 0vw; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// The font-size & responsive-font-size mixin uses RFS to rescale font sizes |
|||
@mixin font-size($fs, $important: false) { |
|||
@include rfs($fs, $important); |
|||
} |
|||
|
|||
@mixin responsive-font-size($fs, $important: false) { |
|||
@include rfs($fs, $important); |
|||
} |
@ -0,0 +1,2 @@ |
|||
/* Give editor access to all of bootstrap. */ |
|||
@import "bootstrap/bootstrap"; |
@ -0,0 +1,18 @@ |
|||
// Import font awesome. |
|||
|
|||
$fa-version: "4.7.0" !default; |
|||
|
|||
@font-face { |
|||
font-family: 'FontAwesome'; |
|||
src: url('[[font:core|fontawesome-webfont.eot]]?v=#{$fa-version}'); |
|||
src: |
|||
url('[[font:core|fontawesome-webfont.eot]]?#iefix&v=#{$fa-version}') format('embedded-opentype'), |
|||
url('[[font:core|fontawesome-webfont.woff2]]?v=#{$fa-version}') format('woff2'), |
|||
url('[[font:core|fontawesome-webfont.woff]]?v=#{$fa-version}') format('woff'), |
|||
url('[[font:core|fontawesome-webfont.ttf]]?v=#{$fa-version}') format('truetype'), |
|||
url('[[font:core|fontawesome-webfont.svg]]?v=#{$fa-version}#fontawesomeregular') format('svg'); |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
} |
|||
|
|||
@import "fontawesome/font-awesome"; |
@ -0,0 +1,220 @@ |
|||
.editor_atto_content_wrap { |
|||
background-color: white; |
|||
color: #333; |
|||
} |
|||
|
|||
.editor_atto_content { |
|||
padding: 4px; |
|||
resize: vertical; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.editor_atto_content_wrap, |
|||
.editor_atto + textarea { |
|||
width: 100%; |
|||
padding: 0; |
|||
} |
|||
|
|||
.editor_atto + textarea { |
|||
border-radius: 0; |
|||
resize: vertical; |
|||
margin-top: -1px; |
|||
} |
|||
|
|||
div.editor_atto_toolbar { |
|||
display: block; |
|||
background: #f2f2f2; |
|||
min-height: 35px; |
|||
border: 1px solid $input-border-color; |
|||
width: 100%; |
|||
padding: 0 0 9px 0; |
|||
} |
|||
|
|||
div.editor_atto_toolbar button { |
|||
padding: 4px 9px; |
|||
background: none; |
|||
border: 0; |
|||
margin: 0; |
|||
border-radius: 0; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
div.editor_atto_toolbar button + button { |
|||
border-left: 1px solid #ccc; |
|||
} |
|||
|
|||
div.editor_atto_toolbar button[disabled] { |
|||
opacity: .45; |
|||
background: none; |
|||
cursor: default; |
|||
} |
|||
|
|||
.editor_atto_toolbar button:hover { |
|||
background-image: radial-gradient(ellipse at center, #fff 60%, #dfdfdf 100%); |
|||
background-color: #ebebeb; |
|||
} |
|||
|
|||
.editor_atto_toolbar button:active, |
|||
.editor_atto_toolbar button.highlight { |
|||
background-image: radial-gradient(ellipse at center, #fff 40%, #dfdfdf 100%); |
|||
background-color: #dfdfdf; |
|||
} |
|||
|
|||
/* Make firefox button sizes match other browsers */ |
|||
div.editor_atto_toolbar button::-moz-focus-inner { |
|||
border: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
div.editor_atto_toolbar button .icon { |
|||
padding: 0; |
|||
margin: 2px 0; |
|||
} |
|||
|
|||
div.editor_atto_toolbar div.atto_group { |
|||
display: inline-block; |
|||
border: 1px solid #ccc; |
|||
border-bottom: 1px solid #b3b3b3; |
|||
border-radius: 4px; |
|||
margin: 9px 0 0 9px; |
|||
background: #fff; |
|||
} |
|||
|
|||
.editor_atto_content img { |
|||
resize: both; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.atto_hasmenu { |
|||
/* IE8 places the images on top of each other if that is not set. */ |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.atto_menuentry .icon { |
|||
width: 16px; |
|||
height: 16px; |
|||
} |
|||
|
|||
.atto_menuentry { |
|||
clear: left; |
|||
} |
|||
|
|||
.atto_menuentry h1, |
|||
.atto_menuentry h2, |
|||
.atto_menuentry p { |
|||
margin: 4px; |
|||
} |
|||
|
|||
/*.atto_form label.sameline { |
|||
display: inline-block; |
|||
min-width: 10em; |
|||
}*/ |
|||
|
|||
.atto_form textarea.fullwidth, |
|||
.atto_form input.fullwidth { |
|||
width: 100%; |
|||
} |
|||
|
|||
.atto_form { |
|||
padding: 0.5rem; |
|||
} |
|||
|
|||
/*.atto_form label { |
|||
display: block; |
|||
margin: 0 0 5px 0; |
|||
}*/ |
|||
|
|||
.atto_control { |
|||
position: absolute; |
|||
right: -6px; |
|||
bottom: -6px; |
|||
display: none; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.atto_control .icon { |
|||
background-color: white; |
|||
} |
|||
|
|||
div.editor_atto_content:focus .atto_control, |
|||
div.editor_atto_content:hover .atto_control { |
|||
display: block; |
|||
} |
|||
|
|||
.editor_atto_menu.yui3-menu-hidden { |
|||
display: none; |
|||
} |
|||
|
|||
/* Get broken images back in firefox */ |
|||
.editor_atto_content img:-moz-broken { |
|||
-moz-force-broken-image-icon: 1; |
|||
min-width: 24px; |
|||
min-height: 24px; |
|||
} |
|||
|
|||
/* Atto menu styling */ |
|||
.moodle-dialogue-base .editor_atto_menu .moodle-dialogue-content .moodle-dialogue-bd { |
|||
padding: 0; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
.editor_atto_menu .dropdown-menu > li > a { |
|||
margin: 3px 14px; |
|||
} |
|||
|
|||
.editor_atto_menu .open ul.dropdown-menu { |
|||
padding-top: 5px; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
.editor_atto_wrap { |
|||
position: relative; |
|||
} |
|||
/*rtl:ignore*/ |
|||
.editor_atto_wrap textarea { |
|||
direction: ltr; |
|||
} |
|||
|
|||
.editor_atto_notification .atto_info, |
|||
.editor_atto_notification .atto_warning { |
|||
display: inline-block; |
|||
background-color: #f2f2f2; |
|||
padding: 0.5em; |
|||
padding-left: 1em; |
|||
padding-right: 1em; |
|||
border-bottom-left-radius: 1em; |
|||
border-bottom-right-radius: 1em; |
|||
} |
|||
|
|||
.editor_atto_notification .atto_info { |
|||
background-color: #f2f2f2; |
|||
} |
|||
|
|||
.editor_atto_notification .atto_warning { |
|||
background-color: #ffd700; |
|||
} |
|||
|
|||
.editor_atto_toolbar, |
|||
.editor_atto_content_wrap, |
|||
.editor_atto + textarea { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.editor_atto_content.form-control { |
|||
width: 100%; |
|||
border-top: 0; |
|||
} |
|||
|
|||
/** Atto fields do not have form-control because that would break the layout of the editor. |
|||
So they need these extra styles to highlight the editor when there is a validation error. */ |
|||
.has-danger .editor_atto_content.form-control, |
|||
.has-danger .editor_atto_content.form-control-danger { |
|||
@include form-validation-state('invalid', $form-feedback-invalid-color, $form-feedback-icon-invalid); |
|||
} |
|||
|
|||
.open.atto_menu > .dropdown-menu { |
|||
display: block; |
|||
} |
|||
div.editor_atto_toolbar button .icon { |
|||
color: $gray-700; |
|||
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue