bobjoll 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/package.json +25 -0
- package/scss/layout/_footer.scss +10 -0
- package/scss/layout/_header.scss +10 -0
- package/scss/modules/_fonts.scss +26 -0
- package/scss/modules/_reset.scss +219 -0
- package/scss/modules/bourbon/addons/_clearfix.scss +25 -0
- package/scss/modules/bourbon/addons/_ellipsis.scss +30 -0
- package/scss/modules/bourbon/addons/_position.scss +48 -0
- package/scss/modules/bourbon/addons/_prefixer.scss +66 -0
- package/scss/modules/bourbon/addons/_size.scss +51 -0
- package/scss/modules/bourbon/addons/_timing-functions.scss +34 -0
- package/scss/modules/bourbon/addons/_triangle.scss +63 -0
- package/scss/modules/bourbon/css3/_calc.scss +4 -0
- package/scss/modules/bourbon/css3/_flex-box.scss +287 -0
- package/scss/modules/bourbon/css3/_keyframes.scss +36 -0
- package/scss/modules/bourbon/css3/_linear-gradient.scss +38 -0
- package/scss/modules/bourbon/css3/_placeholder.scss +8 -0
- package/scss/modules/bourbon/css3/_selection.scss +42 -0
- package/scss/modules/bourbon/css3/_transition.scss +71 -0
- package/scss/modules/mixins/_component.scss +9 -0
- package/scss/modules/mixins/_grid.scss +75 -0
- package/scss/modules/mixins/_helpers.scss +224 -0
- package/scss/modules/variables/_colors.scss +447 -0
- package/scss/modules/variables/_general.scss +235 -0
- package/scss/partials/_accordion-v1-0.scss +165 -0
- package/scss/partials/_autocomplete-v1-0.scss +55 -0
- package/scss/partials/_general-v1-0.scss +51 -0
- package/scss/partials/_grid-v1-0.scss +109 -0
- package/scss/partials/_helper-v1-0.scss +299 -0
- package/scss/partials/_icon-v2-0.scss +323 -0
- package/scss/partials/_list-v1-0.scss +100 -0
- package/scss/partials/_modal-v1-0.scss +159 -0
- package/scss/partials/_notification-v1-1.scss +297 -0
- package/scss/partials/_progress-bar-v1.0.scss +25 -0
- package/scss/partials/_range-v1.0.scss +75 -0
- package/scss/partials/_tooltipFixed-v1.0.scss +128 -0
- package/scss/partials/_typography-v1-0.scss +201 -0
- package/scss/partials/animations/_fade.scss +23 -0
- package/scss/partials/animations/_rotate.scss +11 -0
- package/scss/partials/animations/_scale.scss +23 -0
- package/scss/partials/animations/_slide.scss +31 -0
- package/scss/partials/button-v4-0/_component.scss +304 -0
- package/scss/partials/form/_checkbox-and-radio-v1-0.scss +187 -0
- package/scss/partials/form/_dropdowns-v1-0.scss +323 -0
- package/scss/partials/form/_general-v1-0.scss +166 -0
- package/scss/partials/form/_group-v1-0.scss +157 -0
- package/scss/partials/form/_password-v1-0.scss +28 -0
- package/scss/partials/form/_switch-v1-0.scss +128 -0
- package/scss/partials/form/_upload-v1-0.scss +91 -0
- package/ts/library/common.ts +30 -0
- package/ts/library/cookie.ts +47 -0
- package/ts/library/delegate.ts +122 -0
- package/ts/library/dom.ts +124 -0
- package/ts/library/event.ts +138 -0
- package/ts/library/extend.js +32 -0
- package/ts/library/gr/dom.q.ts +12 -0
- package/ts/library/gr/social/dependency/twitter_pu.js +66 -0
- package/ts/library/gr/social/facebook.ts +154 -0
- package/ts/library/gr/social/google.ts +127 -0
- package/ts/library/gr/social/index.ts +35 -0
- package/ts/library/gr/social/twitter.ts +65 -0
- package/ts/library/helpers.ts +9 -0
- package/ts/library/number-abbreviate.js +57 -0
- package/ts/library/settings.ts +7 -0
- package/ts/library/storage.ts +131 -0
- package/ts/library/svg4everybody.legacy.js +122 -0
- package/ts/partials/accordion-v1.0.ts +104 -0
- package/ts/partials/accordionTabs-v1.0.ts +27 -0
- package/ts/partials/alert-v1.0.ts +51 -0
- package/ts/partials/copy-v1.0.ts +17 -0
- package/ts/partials/countdown-v1.0.ts +119 -0
- package/ts/partials/dropdown-v1.0.ts +247 -0
- package/ts/partials/hbs-v1.0.ts +9 -0
- package/ts/partials/modal-v1.0.ts +213 -0
- package/ts/partials/notifications-v1.1.ts +376 -0
- package/ts/partials/notify-v1.0.ts +746 -0
- package/ts/partials/password-v1.0.ts +19 -0
- package/ts/partials/popover-v1.0.ts +125 -0
- package/ts/partials/progress-bar-v1.0.ts +29 -0
- package/ts/partials/scroll-v1.0.ts +169 -0
- package/ts/partials/scrollable-v1.0.ts +90 -0
- package/ts/partials/tabs-v1.0.ts +79 -0
- package/ts/partials/tags-v1.0.ts +21 -0
- package/ts/partials/trigger-v2.0.ts +155 -0
- package/ts/partials/upload-v1.0.ts +17 -0
- package/ts/views/hbs/alert-v1.0/element.html.hbs +35 -0
- package/ts/views/hbs/countdown-v1.0/countdown-inner.hbs +39 -0
- package/ts/views/hbs/countdown-v1.0/countdown.hbs +4 -0
- package/ts/views/hbs/dropdown-v1.0/element.html.hbs +70 -0
- package/ts/views/hbs/helpers.js +58 -0
- package/ts/views/hbs/modal-v1.0/element.html.hbs +17 -0
- package/ts/views/hbs/notification-v1.1/element-disable.html.hbs +26 -0
- package/ts/views/hbs/notification-v1.1/element.html.hbs +43 -0
- package/ts/views/hbs/notification-v1.1/wrapper.html.hbs +4 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
function getStorage(storageType: string): Storage | null {
|
|
2
|
+
try {
|
|
3
|
+
var storage = (window as any)[storageType + 'Storage'],
|
|
4
|
+
x = '__storage_test__';
|
|
5
|
+
storage.setItem(x, x);
|
|
6
|
+
storage.removeItem(x);
|
|
7
|
+
return storage;
|
|
8
|
+
}
|
|
9
|
+
catch(e) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class ClientStorage
|
|
15
|
+
{
|
|
16
|
+
private backend: Storage | null;
|
|
17
|
+
private dummy: { [key: string]: string } = {};
|
|
18
|
+
|
|
19
|
+
constructor(storageType: 'local' | 'session') {
|
|
20
|
+
this.backend = getStorage(storageType);
|
|
21
|
+
if (!this.backend) {
|
|
22
|
+
this.dummy = {};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
supported(): boolean {
|
|
27
|
+
return !!this.backend;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
removeItem(namespace: string, key: string) {
|
|
31
|
+
const k = namespace !== '' ? `${namespace}/${key}` : key;
|
|
32
|
+
if (this.backend) {
|
|
33
|
+
this.backend.removeItem(k);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.dummy[k];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getAll(namespace: string): {key: string; value: any}[] {
|
|
41
|
+
let namespaceStored: {key: string; value: any}[] = [];
|
|
42
|
+
|
|
43
|
+
if (this.backend) {
|
|
44
|
+
for (let i = 0; i < this.backend.length; i++) {
|
|
45
|
+
let key = this.backend.key(i);
|
|
46
|
+
|
|
47
|
+
if (key && key.match(/namespace/i)) {
|
|
48
|
+
let value = this.get(namespace, key);
|
|
49
|
+
|
|
50
|
+
if (value) {
|
|
51
|
+
namespaceStored.push({key: key, value: value});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return namespaceStored;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getAllKeys(namespace: string): string[] {
|
|
61
|
+
let namespaceKeys: string[] = [];
|
|
62
|
+
|
|
63
|
+
if (this.backend) {
|
|
64
|
+
for (let i = 0; i < this.backend.length; i++) {
|
|
65
|
+
let key = this.backend.key(i);
|
|
66
|
+
|
|
67
|
+
if (key && key.match(new RegExp(namespace, 'i'))) {
|
|
68
|
+
namespaceKeys.push(key);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return namespaceKeys;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getItem(namespace: string, key: string): string | null {
|
|
77
|
+
const k = namespace !== '' ? `${namespace}/${key}` : key;
|
|
78
|
+
return this.backend ? this.backend.getItem(k) : this.dummy[k];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setItem(namespace: string, key: string, value: string) {
|
|
82
|
+
const k = namespace !== '' ? `${namespace}/${key}` : key;
|
|
83
|
+
if (this.backend) {
|
|
84
|
+
this.backend.setItem(k, value);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.dummy[k] = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
remove(namespace: string, key: string): any | null {
|
|
92
|
+
this.removeItem(namespace, key);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get(namespace: string, key: string): any | null {
|
|
96
|
+
return JSON.parse(this.getItem(namespace, key) || 'null');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
set(namespace: string, key: string, value: any) {
|
|
100
|
+
this.setItem(namespace, key, JSON.stringify(value));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
all(namespace: string) {
|
|
104
|
+
return this.getAll(namespace);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
keys(namespace: string) {
|
|
108
|
+
return this.getAllKeys(namespace);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
expired(namespace: string, key: string, expire?: Date) {
|
|
112
|
+
const item = this.getItem(namespace, key);
|
|
113
|
+
const now = new Date();
|
|
114
|
+
|
|
115
|
+
if (!item || now.getTime() > parseInt(item)) {
|
|
116
|
+
if (!expire) {
|
|
117
|
+
expire = new Date();
|
|
118
|
+
expire.setDate(expire.getDate() + 1);
|
|
119
|
+
expire.setHours(0,0,0,0);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.setItem(namespace, key, JSON.stringify(expire.getTime()));
|
|
123
|
+
return true;
|
|
124
|
+
} else {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export let localStorage = new ClientStorage('local');
|
|
131
|
+
export let sessionStorage = new ClientStorage('session');
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
!function(root, factory) {
|
|
2
|
+
"function" == typeof define && define.amd ? // AMD. Register as an anonymous module unless amdModuleId is set
|
|
3
|
+
define([], function() {
|
|
4
|
+
return root.svg4everybody = factory();
|
|
5
|
+
}) : "object" == typeof module && module.exports ? // Node. Does not work with strict CommonJS, but
|
|
6
|
+
// only CommonJS-like environments that support module.exports,
|
|
7
|
+
// like Node.
|
|
8
|
+
module.exports = factory() : root.svg4everybody = factory();
|
|
9
|
+
}(this, function() {
|
|
10
|
+
/*! svg4everybody v2.1.4 | github.com/jonathantneal/svg4everybody */
|
|
11
|
+
function embed(parent, svg, target) {
|
|
12
|
+
// if the target exists
|
|
13
|
+
if (target) {
|
|
14
|
+
// create a document fragment to hold the contents of the target
|
|
15
|
+
var fragment = document.createDocumentFragment(), viewBox = !svg.hasAttribute("viewBox") && target.getAttribute("viewBox");
|
|
16
|
+
// conditionally set the viewBox on the svg
|
|
17
|
+
viewBox && svg.setAttribute("viewBox", viewBox);
|
|
18
|
+
// copy the contents of the clone into the fragment
|
|
19
|
+
for (// clone the target
|
|
20
|
+
var clone = target.cloneNode(!0); clone.childNodes.length; ) {
|
|
21
|
+
fragment.appendChild(clone.firstChild);
|
|
22
|
+
}
|
|
23
|
+
// append the fragment into the svg
|
|
24
|
+
parent.appendChild(fragment);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function loadreadystatechange(xhr) {
|
|
28
|
+
// listen to changes in the request
|
|
29
|
+
xhr.onreadystatechange = function() {
|
|
30
|
+
// if the request is ready
|
|
31
|
+
if (4 === xhr.readyState) {
|
|
32
|
+
// get the cached html document
|
|
33
|
+
var cachedDocument = xhr._cachedDocument;
|
|
34
|
+
// ensure the cached html document based on the xhr response
|
|
35
|
+
cachedDocument || (cachedDocument = xhr._cachedDocument = document.implementation.createHTMLDocument(""),
|
|
36
|
+
cachedDocument.body.innerHTML = xhr.responseText, xhr._cachedTarget = {}), // clear the xhr embeds list and embed each item
|
|
37
|
+
xhr._embeds.splice(0).map(function(item) {
|
|
38
|
+
// get the cached target
|
|
39
|
+
var target = xhr._cachedTarget[item.id];
|
|
40
|
+
// ensure the cached target
|
|
41
|
+
target || (target = xhr._cachedTarget[item.id] = cachedDocument.getElementById(item.id)),
|
|
42
|
+
// embed the target into the svg
|
|
43
|
+
embed(item.parent, item.svg, target);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}, // test the ready state change immediately
|
|
47
|
+
xhr.onreadystatechange();
|
|
48
|
+
}
|
|
49
|
+
function svg4everybody(rawopts) {
|
|
50
|
+
function oninterval() {
|
|
51
|
+
// while the index exists in the live <use> collection
|
|
52
|
+
for (// get the cached <use> index
|
|
53
|
+
var index = 0; index < uses.length; ) {
|
|
54
|
+
// get the current <use>
|
|
55
|
+
var use = uses[index], parent = use.parentNode, svg = getSVGAncestor(parent);
|
|
56
|
+
if (svg) {
|
|
57
|
+
var src = use.getAttribute("xlink:href") || use.getAttribute("href");
|
|
58
|
+
// if running with legacy support
|
|
59
|
+
if (nosvg) {
|
|
60
|
+
// create a new fallback image
|
|
61
|
+
var img = document.createElement("img");
|
|
62
|
+
// force display in older IE
|
|
63
|
+
img.style.cssText = "display:inline-block;height:100%;width:100%", // set the fallback size using the svg size
|
|
64
|
+
img.setAttribute("width", svg.getAttribute("width") || svg.clientWidth), img.setAttribute("height", svg.getAttribute("height") || svg.clientHeight),
|
|
65
|
+
// set the fallback src
|
|
66
|
+
img.src = fallback(src, svg, use), // replace the <use> with the fallback image
|
|
67
|
+
parent.replaceChild(img, use);
|
|
68
|
+
} else {
|
|
69
|
+
if (polyfill && (!opts.validate || opts.validate(src, svg, use))) {
|
|
70
|
+
// remove the <use> element
|
|
71
|
+
parent.removeChild(use);
|
|
72
|
+
// parse the src and get the url and id
|
|
73
|
+
var srcSplit = src.split("#"), url = srcSplit.shift(), id = srcSplit.join("#");
|
|
74
|
+
// if the link is external
|
|
75
|
+
if (url.length) {
|
|
76
|
+
// get the cached xhr request
|
|
77
|
+
var xhr = requests[url];
|
|
78
|
+
// ensure the xhr request exists
|
|
79
|
+
xhr || (xhr = requests[url] = new XMLHttpRequest(), xhr.open("GET", url), xhr.send(),
|
|
80
|
+
xhr._embeds = []), // add the svg and id as an item to the xhr embeds list
|
|
81
|
+
xhr._embeds.push({
|
|
82
|
+
parent: parent,
|
|
83
|
+
svg: svg,
|
|
84
|
+
id: id
|
|
85
|
+
}), // prepare the xhr ready state change event
|
|
86
|
+
loadreadystatechange(xhr);
|
|
87
|
+
} else {
|
|
88
|
+
// embed the local id into the svg
|
|
89
|
+
embed(parent, document.getElementById(id));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
// increase the index when the previous value was not "valid"
|
|
95
|
+
++index;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// continue the interval
|
|
99
|
+
requestAnimationFrame(oninterval, 67);
|
|
100
|
+
}
|
|
101
|
+
var nosvg, fallback, opts = Object(rawopts);
|
|
102
|
+
// configure the fallback method
|
|
103
|
+
fallback = opts.fallback || function(src) {
|
|
104
|
+
return src.replace(/\?[^#]+/, "").replace("#", ".").replace(/^\./, "") + ".png" + (/\?[^#]+/.exec(src) || [ "" ])[0];
|
|
105
|
+
}, // set whether to shiv <svg> and <use> elements and use image fallbacks
|
|
106
|
+
nosvg = "nosvg" in opts ? opts.nosvg : /\bMSIE [1-8]\b/.test(navigator.userAgent),
|
|
107
|
+
// conditionally shiv <svg> and <use>
|
|
108
|
+
nosvg && (document.createElement("svg"), document.createElement("use"));
|
|
109
|
+
// set whether the polyfill will be activated or not
|
|
110
|
+
var polyfill, olderIEUA = /\bMSIE [1-8]\.0\b/, newerIEUA = /\bTrident\/[567]\b|\bMSIE (?:9|10)\.0\b/, webkitUA = /\bAppleWebKit\/(\d+)\b/, olderEdgeUA = /\bEdge\/12\.(\d+)\b/;
|
|
111
|
+
polyfill = "polyfill" in opts ? opts.polyfill : olderIEUA.test(navigator.userAgent) || newerIEUA.test(navigator.userAgent) || (navigator.userAgent.match(olderEdgeUA) || [])[1] < 10547 || (navigator.userAgent.match(webkitUA) || [])[1] < 537;
|
|
112
|
+
// create xhr requests object
|
|
113
|
+
var requests = {}, requestAnimationFrame = window.requestAnimationFrame || setTimeout, uses = document.getElementsByTagName("use");
|
|
114
|
+
// conditionally start the interval if the polyfill is active
|
|
115
|
+
polyfill && oninterval();
|
|
116
|
+
}
|
|
117
|
+
function getSVGAncestor(node) {
|
|
118
|
+
for (var svg = node; "svg" !== svg.nodeName.toLowerCase() && (svg = svg.parentNode); ) {}
|
|
119
|
+
return svg;
|
|
120
|
+
}
|
|
121
|
+
return svg4everybody;
|
|
122
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import 'bobjoll/ts/library/common';
|
|
2
|
+
import { delegate, delegateRemove, qq } from 'bobjoll/ts/library/dom';
|
|
3
|
+
import { IsUrlValid } from 'bobjoll/ts/library/helpers';
|
|
4
|
+
|
|
5
|
+
class Accordion {
|
|
6
|
+
private static instance: Accordion | null;
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
if (!Accordion.instance) {
|
|
10
|
+
Accordion.instance = this;
|
|
11
|
+
this.setup();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return Accordion.instance;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private static addEventListeners() {
|
|
18
|
+
delegate('.accordion__link', 'click', Accordion.eventClickHandler);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private static setupMobileNavigation() {
|
|
22
|
+
qq('.accordion:not(.accordion--ready)').forEach(element => {
|
|
23
|
+
const options = qq('.accordion__container > a, .accordion__container > button', element).reduce((acc, link, index) => {
|
|
24
|
+
if (!('' == element.dataset.disableMobileSelect)) {
|
|
25
|
+
link.classList.add('hide-tablet');
|
|
26
|
+
}
|
|
27
|
+
acc += `<option value="${index}">${link.innerHTML}</option>`;
|
|
28
|
+
return acc;
|
|
29
|
+
}, '');
|
|
30
|
+
|
|
31
|
+
if (!('' == element.dataset.disableMobileSelect)) {
|
|
32
|
+
element.insertAdjacentHTML(
|
|
33
|
+
'afterbegin',
|
|
34
|
+
`
|
|
35
|
+
<li class="accordion__mobile-nav show-tablet">
|
|
36
|
+
<div class="accordion__select__wrapper">
|
|
37
|
+
<select class="accordion__select">${options}</select>
|
|
38
|
+
</div>
|
|
39
|
+
</li>
|
|
40
|
+
`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
element.classList.add('accordion--ready');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
qq('.accordion__select').forEach(select => select.addEventListener('change', Accordion.eventSelectChangeHandler));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private static eventClickHandler(this: HTMLElement) {
|
|
51
|
+
const wrapper = <HTMLElement | undefined>this.parent('.accordion');
|
|
52
|
+
|
|
53
|
+
if (wrapper) {
|
|
54
|
+
const collapsible = 'true' === (wrapper.dataset.collapsible || wrapper.dataset.closable);
|
|
55
|
+
|
|
56
|
+
qq('.accordion__link', wrapper).forEach(item => (item !== this ? item.classList.remove('active') : null));
|
|
57
|
+
|
|
58
|
+
(wrapper.classList as any)[collapsible ? 'toggle' : 'add']('active');
|
|
59
|
+
(this.classList as any)[collapsible ? 'toggle' : 'add']('active');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private static eventSelectChangeHandler(this: HTMLSelectElement) {
|
|
64
|
+
const indexActive = parseFloat(this.value);
|
|
65
|
+
const wrapper = this.parent('.accordion');
|
|
66
|
+
|
|
67
|
+
if (wrapper && 'number' === typeof indexActive) {
|
|
68
|
+
qq('.accordion__container > a, .accordion__container > button', wrapper as HTMLElement).forEach((button, index) => {
|
|
69
|
+
const href = button.getAttribute('href');
|
|
70
|
+
|
|
71
|
+
if (button.classList.contains('accordion__link')) {
|
|
72
|
+
if (indexActive === index) {
|
|
73
|
+
button.click();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
button.classList[indexActive === index ? 'add' : 'remove']('active');
|
|
77
|
+
} else if (href && indexActive === index && IsUrlValid(href)) {
|
|
78
|
+
window.location.href = href;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public refresh() {
|
|
85
|
+
Accordion.setupMobileNavigation();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public destroy() {
|
|
89
|
+
qq('.accordion__select').forEach(select => select.removeEventListener('change', Accordion.eventSelectChangeHandler));
|
|
90
|
+
|
|
91
|
+
delegateRemove('.accordion__link', 'click', Accordion.addEventListeners);
|
|
92
|
+
|
|
93
|
+
Accordion.instance = null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private setup() {
|
|
97
|
+
Accordion.setupMobileNavigation();
|
|
98
|
+
Accordion.addEventListeners();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const accordion = new Accordion();
|
|
103
|
+
|
|
104
|
+
export default accordion;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { delegate, qq } from "../library/delegate";
|
|
2
|
+
|
|
3
|
+
const getActiveIndex = (parent: HTMLElement): number => {
|
|
4
|
+
return qq('header li', parent).reduce((acc, link, index) =>
|
|
5
|
+
((acc = link.classList.contains('active') ? index : acc), acc),
|
|
6
|
+
0
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const showActiveTab = (parent: HTMLElement) => {
|
|
11
|
+
const index = getActiveIndex(parent);
|
|
12
|
+
qq('header ~ .content', parent).forEach((element, i) =>
|
|
13
|
+
element.classList[i === index ? 'add' : 'remove']('show')
|
|
14
|
+
);
|
|
15
|
+
window.dispatchEvent(new Event('resize'));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const handlerHeaderLink = function(this: HTMLElement) {
|
|
19
|
+
const accordionTabElement = this.parent('.accordion-tabs') as HTMLElement|undefined;
|
|
20
|
+
if (accordionTabElement) {
|
|
21
|
+
qq('header li.active', accordionTabElement).forEach(element => element.classList.remove('active'));
|
|
22
|
+
this.classList.add('active');
|
|
23
|
+
showActiveTab(accordionTabElement);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
delegate('.accordion-tabs header li', 'click', handlerHeaderLink);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// tslint:disable-next-line:import-name
|
|
2
|
+
import Notification, { Position } from 'BobjollNotifications';
|
|
3
|
+
import View from 'BobjollView';
|
|
4
|
+
|
|
5
|
+
const EXT = View.ext;
|
|
6
|
+
const extend = require('bobjoll/ts/library/extend');
|
|
7
|
+
|
|
8
|
+
type AlertType = 'success' | 'warning' | 'error';
|
|
9
|
+
|
|
10
|
+
export interface InsertSettings {
|
|
11
|
+
fixed?: boolean;
|
|
12
|
+
class: AlertType;
|
|
13
|
+
html: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DefaultSettings {
|
|
17
|
+
fixed: boolean;
|
|
18
|
+
recurrent: boolean;
|
|
19
|
+
timeout: number;
|
|
20
|
+
template: Function;
|
|
21
|
+
position: keyof Position;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Settings {
|
|
25
|
+
fixed?: boolean;
|
|
26
|
+
timeout?: number;
|
|
27
|
+
template?: Function;
|
|
28
|
+
position?: keyof Position;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default class Alert extends Notification {
|
|
32
|
+
constructor(settings?: Settings) {
|
|
33
|
+
const defaultSettings = {
|
|
34
|
+
recurrent: false,
|
|
35
|
+
fixed: false,
|
|
36
|
+
timeout: 5000,
|
|
37
|
+
template: require(`BobjollTemplate/alert-v1.0/element.${EXT}`),
|
|
38
|
+
position: 'top-right'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
super(extend(defaultSettings, settings));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public new(html: string, type: AlertType, fixed = false) {
|
|
45
|
+
return super.insert({
|
|
46
|
+
fixed: fixed,
|
|
47
|
+
html: html,
|
|
48
|
+
class: `notification--${type}`
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default function(text: string) {
|
|
2
|
+
const textarea = document.createElement('textarea');
|
|
3
|
+
|
|
4
|
+
textarea.textContent = text;
|
|
5
|
+
textarea.style.position = 'fixed';
|
|
6
|
+
|
|
7
|
+
document.body.appendChild(textarea);
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
textarea.select();
|
|
11
|
+
document.execCommand('copy');
|
|
12
|
+
} catch(err) {
|
|
13
|
+
console.warn('Copy to clipboard failed.', err);
|
|
14
|
+
} finally {
|
|
15
|
+
document.body.removeChild(textarea);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { q } from 'bobjoll/ts/library/gr/dom.q';
|
|
2
|
+
|
|
3
|
+
export default class Countdown {
|
|
4
|
+
private static readonly outer: Function = require('BobjollTemplate/countdown-v1.0/countdown.hbs');
|
|
5
|
+
private static readonly inner: Function = require('BobjollTemplate/countdown-v1.0/countdown-inner.hbs');
|
|
6
|
+
|
|
7
|
+
private element: HTMLElement;
|
|
8
|
+
private settings: CountdownSettings;
|
|
9
|
+
private interval: any;
|
|
10
|
+
|
|
11
|
+
constructor(settings: CountdownSettings) {
|
|
12
|
+
this.settings = settings;
|
|
13
|
+
|
|
14
|
+
if (this.settings.container.classList.contains('countdown')) {
|
|
15
|
+
this.element = this.settings.container;
|
|
16
|
+
} else {
|
|
17
|
+
this.settings.container.insertAdjacentHTML('beforeend', Countdown.outer());
|
|
18
|
+
|
|
19
|
+
this.element = q('.countdown', this.settings.container) || document.createElement('div');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
this.setup();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private static normalize(number: number) {
|
|
26
|
+
if (number < 10) {
|
|
27
|
+
return '0' + number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private static count(options: CountdownSettings) {
|
|
34
|
+
const _distance = options.dateEnd.getTime() - new Date().getTime();
|
|
35
|
+
const _second = 1000;
|
|
36
|
+
const _minute = _second * 60;
|
|
37
|
+
const _hour = _minute * 60;
|
|
38
|
+
const _day = _hour * 24;
|
|
39
|
+
|
|
40
|
+
let date: {
|
|
41
|
+
Days?: number | string;
|
|
42
|
+
Hours?: number | string;
|
|
43
|
+
Mins?: number | string;
|
|
44
|
+
Secs?: number | string;
|
|
45
|
+
} = {};
|
|
46
|
+
let days = Countdown.normalize(Math.floor(_distance / _day));
|
|
47
|
+
|
|
48
|
+
if (days > 0) {
|
|
49
|
+
date.Days = days;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
date.Hours = Countdown.normalize(Math.floor((_distance % _day) / _hour));
|
|
53
|
+
date.Mins = Countdown.normalize(Math.floor((_distance % _hour) / _minute));
|
|
54
|
+
date.Secs = Countdown.normalize(Math.floor((_distance % _minute) / _second));
|
|
55
|
+
|
|
56
|
+
if (_distance < 0) return;
|
|
57
|
+
|
|
58
|
+
return date;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private static countLeft(options: CountdownSettings) {
|
|
62
|
+
if (!options.dateStart || !options.total) return;
|
|
63
|
+
|
|
64
|
+
const dateCurrent = new Date();
|
|
65
|
+
const timeTotal = options.dateEnd.getTime() - options.dateStart.getTime();
|
|
66
|
+
const timeLeft = options.dateEnd.getTime() - dateCurrent.getTime();
|
|
67
|
+
const total = Math.round(Math.abs((timeLeft / timeTotal) * options.total))
|
|
68
|
+
.toString()
|
|
69
|
+
.split('');
|
|
70
|
+
|
|
71
|
+
if (timeLeft <= 0 || !(dateCurrent >= options.dateStart && dateCurrent <= options.dateEnd)) {
|
|
72
|
+
return '0000'.toString().split('');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (total.length < options.total.toString().length) {
|
|
76
|
+
const loop = options.total.toString().length - total.length;
|
|
77
|
+
for (let i = 0; i < loop; i++) {
|
|
78
|
+
total.unshift('0');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return total;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private setup() {
|
|
86
|
+
let method: Function = Countdown.count;
|
|
87
|
+
|
|
88
|
+
if (this.settings.dateStart && this.settings.total) {
|
|
89
|
+
method = Countdown.countLeft;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.element.innerHTML = Countdown.inner({
|
|
93
|
+
date: method(this.settings),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
this.interval = setInterval(() => {
|
|
97
|
+
const date = method(this.settings);
|
|
98
|
+
|
|
99
|
+
let data: any = {};
|
|
100
|
+
|
|
101
|
+
if (date) {
|
|
102
|
+
data['date'] = date;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.element.innerHTML = Countdown.inner(data);
|
|
106
|
+
|
|
107
|
+
if (new Date().getTime() >= this.settings.dateEnd.getTime()) {
|
|
108
|
+
clearInterval(this.interval);
|
|
109
|
+
}
|
|
110
|
+
}, 1000);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface CountdownSettings {
|
|
115
|
+
container: HTMLElement;
|
|
116
|
+
dateStart?: Date;
|
|
117
|
+
dateEnd: Date;
|
|
118
|
+
total?: number;
|
|
119
|
+
}
|