@commversion/libs 0.2.0-2 → 0.3.0-alpha.1
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/.prettierignore +4 -0
- package/.release-it.json +5 -0
- package/README.md +19 -4
- package/_templates/generator/help/index.ejs.t +5 -0
- package/_templates/generator/new/hello.ejs.t +18 -0
- package/_templates/generator/with-prompt/hello.ejs.t +18 -0
- package/_templates/generator/with-prompt/prompt.js +14 -0
- package/_templates/scripts/new/dev-build-scripts.ejs.t +7 -0
- package/_templates/scripts/new/readme.ejs.t +14 -0
- package/_templates/scripts/new/root-readme.ejs.t +6 -0
- package/_templates/scripts/new/src_index_html.ejs.t +60 -0
- package/_templates/scripts/new/src_main.ejs.t +8 -0
- package/_templates/scripts/new/src_script.ejs.t +9 -0
- package/_templates/scripts/new/tests_script.ejs.t +9 -0
- package/_templates/scripts/new/vite-config.ejs.t +20 -0
- package/dist/lc-input-error.js +1 -0
- package/dist/lc-show-hide.js +1 -0
- package/package.json +17 -8
- package/scripts/lc-exit-intent/README.md +21 -0
- package/scripts/lc-exit-intent/src/exit-intent.js +23 -0
- package/scripts/lc-exit-intent/src/index.html +52 -0
- package/scripts/lc-exit-intent/src/main.js +3 -0
- package/scripts/lc-exit-intent/tests/exit-intent.test.js +52 -0
- package/scripts/lc-exit-intent/vite.config.js +17 -0
- package/scripts/lc-ga-tags/README.md +19 -0
- package/scripts/lc-ga-tags/src/append-ga-session.js +11 -0
- package/scripts/lc-ga-tags/src/index.html +66 -0
- package/scripts/lc-ga-tags/src/main.js +3 -0
- package/scripts/lc-ga-tags/tests/append-ga-session.test.js +33 -0
- package/scripts/lc-ga-tags/vite.config.js +17 -0
- package/scripts/lc-input-error/README.md +22 -0
- package/scripts/lc-input-error/src/index.html +74 -0
- package/scripts/lc-input-error/src/input-error.js +13 -0
- package/scripts/lc-input-error/src/main.js +3 -0
- package/scripts/lc-input-error/tests/input-error.test.js +27 -0
- package/scripts/lc-input-error/vite.config.js +17 -0
- package/scripts/lc-show-hide/README.md +45 -0
- package/scripts/lc-show-hide/src/index.html +58 -0
- package/scripts/lc-show-hide/src/main.js +5 -0
- package/scripts/lc-show-hide/src/predicate-functions.js +11 -0
- package/scripts/lc-show-hide/src/show-hide.js +49 -0
- package/scripts/lc-show-hide/tests/predicate-functions.test.js +31 -0
- package/scripts/lc-show-hide/vite.config.js +17 -0
- package/scripts/schedule-event/README.md +58 -0
- package/scripts/schedule-event/src/index.html +14 -0
- package/scripts/schedule-event/src/main.js +13 -0
- package/scripts/schedule-event/src/parse-schedule.js +16 -0
- package/scripts/schedule-event/src/schedule-event.js +18 -0
- package/scripts/schedule-event/tests/parse-schedule.test.js +51 -0
- package/scripts/schedule-event/tests/schedule-event.test.js +23 -0
- package/scripts/schedule-event/vite.config.js +17 -0
package/.prettierignore
ADDED
package/.release-it.json
ADDED
package/README.md
CHANGED
|
@@ -23,6 +23,16 @@ Configuration takes place by global `window.commversion` object, make sure to no
|
|
|
23
23
|
</script>
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## Available scripts
|
|
27
|
+
|
|
28
|
+
All scripts are available under the `scripts/` directory.
|
|
29
|
+
|
|
30
|
+
- lc-exit-intent
|
|
31
|
+
- lc-ga-tags
|
|
32
|
+
- lc-input-errors
|
|
33
|
+
- lc-show-hide
|
|
34
|
+
- schedule-event
|
|
35
|
+
|
|
26
36
|
## Release new versions
|
|
27
37
|
|
|
28
38
|
The project follows the semantic versioning convention.
|
|
@@ -31,11 +41,16 @@ Patch releases for bug fixes.
|
|
|
31
41
|
Minor releases for new features.
|
|
32
42
|
Major releases for breaking changes.
|
|
33
43
|
|
|
34
|
-
The release is fully automated by executing `npm run release`.
|
|
44
|
+
The release is fully automated by executing `npm run release`. No need to run build scripts beforehand, this is done automatically.
|
|
35
45
|
|
|
36
46
|
## Guideline for contributing
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
To create a new script, run the following command in a shell.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
$ npx hygen scripts new script-name
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The command above will create e new script containing the absolute minimum files. It will also amend root `README.md` and `package.json` to include required entries.
|
|
40
55
|
|
|
41
|
-
|
|
56
|
+
Start working on a specific script by running `npm run package:dev`.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
|
|
3
|
+
---
|
|
4
|
+
---
|
|
5
|
+
to: app/hello.js
|
|
6
|
+
---
|
|
7
|
+
const hello = ```
|
|
8
|
+
Hello!
|
|
9
|
+
This is your first hygen template.
|
|
10
|
+
|
|
11
|
+
Learn what it can do here:
|
|
12
|
+
|
|
13
|
+
https://github.com/jondot/hygen
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
console.log(hello)
|
|
17
|
+
|
|
18
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: _templates/<%= name %>/<%= action || 'new' %>/hello.ejs.t
|
|
3
|
+
---
|
|
4
|
+
---
|
|
5
|
+
to: app/hello.js
|
|
6
|
+
---
|
|
7
|
+
const hello = ```
|
|
8
|
+
Hello!
|
|
9
|
+
This is your first prompt based hygen template.
|
|
10
|
+
|
|
11
|
+
Learn what it can do here:
|
|
12
|
+
|
|
13
|
+
https://github.com/jondot/hygen
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
console.log(hello)
|
|
17
|
+
|
|
18
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: _templates/<%= name %>/<%= action || 'new' %>/prompt.js
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
// see types of prompts:
|
|
6
|
+
// https://github.com/enquirer/enquirer/tree/master/examples
|
|
7
|
+
//
|
|
8
|
+
module.exports = [
|
|
9
|
+
{
|
|
10
|
+
type: 'input',
|
|
11
|
+
name: 'message',
|
|
12
|
+
message: "What's your message?"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: scripts/<%= name %>/README.md
|
|
3
|
+
---
|
|
4
|
+
# Package name
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
Document how this script is supposed to be installed.
|
|
9
|
+
Make sure any configuration requirements are explained here.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Document how this script is supposed to be used.
|
|
14
|
+
Provide examples for different use cases.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: scripts/<%= name %>/src/index.html
|
|
3
|
+
---
|
|
4
|
+
<html>
|
|
5
|
+
<body>
|
|
6
|
+
<!-- Start of LiveChat (www.livechatinc.com) code -->
|
|
7
|
+
<script>
|
|
8
|
+
window.__lc = window.__lc || {};
|
|
9
|
+
window.__lc.license = 10793607;
|
|
10
|
+
(function (n, t, c) {
|
|
11
|
+
function i(n) {
|
|
12
|
+
return e._h ? e._h.apply(null, n) : e._q.push(n);
|
|
13
|
+
}
|
|
14
|
+
var e = {
|
|
15
|
+
_q: [],
|
|
16
|
+
_h: null,
|
|
17
|
+
_v: "2.0",
|
|
18
|
+
on: function () {
|
|
19
|
+
i(["on", c.call(arguments)]);
|
|
20
|
+
},
|
|
21
|
+
once: function () {
|
|
22
|
+
i(["once", c.call(arguments)]);
|
|
23
|
+
},
|
|
24
|
+
off: function () {
|
|
25
|
+
i(["off", c.call(arguments)]);
|
|
26
|
+
},
|
|
27
|
+
get: function () {
|
|
28
|
+
if (!e._h)
|
|
29
|
+
throw new Error(
|
|
30
|
+
"[LiveChatWidget] You can't use getters before load."
|
|
31
|
+
);
|
|
32
|
+
return i(["get", c.call(arguments)]);
|
|
33
|
+
},
|
|
34
|
+
call: function () {
|
|
35
|
+
i(["call", c.call(arguments)]);
|
|
36
|
+
},
|
|
37
|
+
init: function () {
|
|
38
|
+
var n = t.createElement("script");
|
|
39
|
+
(n.async = !0),
|
|
40
|
+
(n.type = "text/javascript"),
|
|
41
|
+
(n.src = "https://cdn.livechatinc.com/tracking.js"),
|
|
42
|
+
t.head.appendChild(n);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
!n.__lc.asyncInit && e.init(),
|
|
46
|
+
(n.LiveChatWidget = n.LiveChatWidget || e);
|
|
47
|
+
})(window, document, [].slice);
|
|
48
|
+
</script>
|
|
49
|
+
<!-- End of LiveChat code -->
|
|
50
|
+
|
|
51
|
+
<script async src="./main.js" type="module"></script>
|
|
52
|
+
<script>
|
|
53
|
+
window.commversion = {
|
|
54
|
+
key: "value"
|
|
55
|
+
}
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<h1><%= name %></h1>
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: scripts/<%= name %>/src/<%= name %>.js
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
export const <%= h.changeCase.camel(name) %> = (configuration) => ({state, customerData}) => {
|
|
6
|
+
const { LiveChatWidget } = window;
|
|
7
|
+
|
|
8
|
+
console.log({configuration, state, customerData, LiveChatWidget});
|
|
9
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
to: scripts/<%= name %>/vite.config.js
|
|
3
|
+
---
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
const config = {
|
|
7
|
+
build: {
|
|
8
|
+
outDir: path.resolve("dist"),
|
|
9
|
+
emptyOutDir: false,
|
|
10
|
+
target: "es2015",
|
|
11
|
+
lib: {
|
|
12
|
+
entry: path.resolve(__dirname, "src/main.js"),
|
|
13
|
+
name: "<%= h.changeCase.camel(name) %>",
|
|
14
|
+
fileName: () => "<%= name %>.js",
|
|
15
|
+
formats: ["iife"],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default config;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";const t=()=>{const{LiveChatWidget:e}=window;document.querySelectorAll("input").forEach(n=>{n.addEventListener("invalid",()=>{e.call("update_session_variables",{input_error:"true"})})})};window.LiveChatWidget.on("ready",t)})();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";const i=(e,o)=>!e.test(o),t=(e,o)=>e.test(o),s=["browsing"],d=e=>e.show&&e.hide?{predicateFn:()=>console.error("Cannot set both show and hide configuration. Please choose one.")}:e.show?{predicateFn:i,pluginConfiguration:e.show}:e.hide?{predicateFn:t,pluginConfiguration:e.hide}:{predicateFn:()=>console.error("No configuration for show/hide script.")},r=e=>({customerData:o})=>{const{LiveChatWidget:n}=window,c=window.location.pathname,{predicateFn:h,pluginConfiguration:u}=d(e);h(new RegExp(u),c)&&s.includes(o.status)&&n.call("hide")};window.commversion=window.commversion||{},window.LiveChatWidget.on("ready",r(window.commversion))})();
|
package/package.json
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commversion/libs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-alpha.1",
|
|
4
4
|
"author": "Marios Antonoudiou <mariosant@sent.com>",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"lint": "prettier -c .",
|
|
8
|
-
"test": "wtr ./
|
|
8
|
+
"test": "wtr ./scripts/**/*.test.js --node-resolve",
|
|
9
9
|
"prepack": "concurrently npm:build:*",
|
|
10
10
|
"release": "release-it",
|
|
11
|
-
"dev:
|
|
12
|
-
"build:
|
|
13
|
-
"dev:
|
|
14
|
-
"build:
|
|
15
|
-
"dev:lc-
|
|
16
|
-
"build:lc-
|
|
11
|
+
"dev:lc-show-hide": "vite serve scripts/lc-show-hide/src/",
|
|
12
|
+
"build:lc-show-hide": "vite build -c scripts/lc-show-hide/vite.config.js",
|
|
13
|
+
"dev:schedule-event": "vite serve scripts/schedule-event/src/",
|
|
14
|
+
"build:schedule-event": "vite build -c scripts/schedule-event/vite.config.js",
|
|
15
|
+
"dev:lc-ga-tags": "vite serve scripts/lc-ga-tags/src/",
|
|
16
|
+
"build:lc-ga-tags": "vite build -c scripts/lc-ga-tags/vite.config.js",
|
|
17
|
+
"dev:lc-exit-intent": "vite serve scripts/lc-exit-intent/src/",
|
|
18
|
+
"build:lc-exit-intent": "vite build -c scripts/lc-exit-intent/vite.config.js",
|
|
19
|
+
"dev:lc-input-error": "vite serve scripts/lc-input-error/src/",
|
|
20
|
+
"build:lc-input-error": "vite build -c scripts/lc-input-error/vite.config.js"
|
|
17
21
|
},
|
|
18
22
|
"publishConfig": {
|
|
19
23
|
"access": "public"
|
|
@@ -24,12 +28,17 @@
|
|
|
24
28
|
"@web/test-runner": "^0.13.22",
|
|
25
29
|
"chai": "^4.3.4",
|
|
26
30
|
"concurrently": "^6.5.0",
|
|
31
|
+
"hygen": "^6.1.0",
|
|
27
32
|
"prettier": "^2.5.0",
|
|
28
33
|
"release-it": "^14.11.8",
|
|
34
|
+
"rimraf": "^3.0.2",
|
|
29
35
|
"sinon": "^12.0.1",
|
|
30
36
|
"vite": "^2.7.3"
|
|
31
37
|
},
|
|
32
38
|
"dependencies": {
|
|
33
39
|
"spacetime": "^6.16.3"
|
|
40
|
+
},
|
|
41
|
+
"volta": {
|
|
42
|
+
"node": "16.13.2"
|
|
34
43
|
}
|
|
35
44
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# LiveChat Exit Intent
|
|
2
|
+
|
|
3
|
+
Help target visitors intending to exit the website.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Use the following snippet to install the plugin to website _after_ LiveChat and Google Analytics tags.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script
|
|
11
|
+
async
|
|
12
|
+
src="https://cdn.jsdelivr.net/npm/@commversion/libs@version/dist/lc-exit-intent.js"
|
|
13
|
+
></script>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
The script does not need any configuration. It should work out of the box.
|
|
19
|
+
To validate it works properly, look for `exit_intent` on LiveChat visitor custom data.
|
|
20
|
+
|
|
21
|
+
Possible values for `exit_intent` are `true` and `false`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const exitIntent = () => {
|
|
2
|
+
const { LiveChatWidget } = window;
|
|
3
|
+
|
|
4
|
+
LiveChatWidget.call("update_session_variables", {
|
|
5
|
+
exit_intent: "false",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
document.addEventListener("mouseleave", () => {
|
|
9
|
+
const { status } = LiveChatWidget.get("customer_data");
|
|
10
|
+
|
|
11
|
+
if (status === "browsing") {
|
|
12
|
+
LiveChatWidget.call("update_session_variables", {
|
|
13
|
+
exit_intent: "true",
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
document.addEventListener("mouseenter", () => {
|
|
19
|
+
LiveChatWidget.call("update_session_variables", {
|
|
20
|
+
exit_intent: "false",
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<body>
|
|
3
|
+
<!-- Start of LiveChat (www.livechatinc.com) code -->
|
|
4
|
+
<script>
|
|
5
|
+
window.__lc = window.__lc || {};
|
|
6
|
+
window.__lc.license = 10793607;
|
|
7
|
+
(function (n, t, c) {
|
|
8
|
+
function i(n) {
|
|
9
|
+
return e._h ? e._h.apply(null, n) : e._q.push(n);
|
|
10
|
+
}
|
|
11
|
+
var e = {
|
|
12
|
+
_q: [],
|
|
13
|
+
_h: null,
|
|
14
|
+
_v: "2.0",
|
|
15
|
+
on: function () {
|
|
16
|
+
i(["on", c.call(arguments)]);
|
|
17
|
+
},
|
|
18
|
+
once: function () {
|
|
19
|
+
i(["once", c.call(arguments)]);
|
|
20
|
+
},
|
|
21
|
+
off: function () {
|
|
22
|
+
i(["off", c.call(arguments)]);
|
|
23
|
+
},
|
|
24
|
+
get: function () {
|
|
25
|
+
if (!e._h)
|
|
26
|
+
throw new Error(
|
|
27
|
+
"[LiveChatWidget] You can't use getters before load."
|
|
28
|
+
);
|
|
29
|
+
return i(["get", c.call(arguments)]);
|
|
30
|
+
},
|
|
31
|
+
call: function () {
|
|
32
|
+
i(["call", c.call(arguments)]);
|
|
33
|
+
},
|
|
34
|
+
init: function () {
|
|
35
|
+
var n = t.createElement("script");
|
|
36
|
+
(n.async = !0),
|
|
37
|
+
(n.type = "text/javascript"),
|
|
38
|
+
(n.src = "https://cdn.livechatinc.com/tracking.js"),
|
|
39
|
+
t.head.appendChild(n);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
!n.__lc.asyncInit && e.init(),
|
|
43
|
+
(n.LiveChatWidget = n.LiveChatWidget || e);
|
|
44
|
+
})(window, document, [].slice);
|
|
45
|
+
</script>
|
|
46
|
+
<!-- End of LiveChat code -->
|
|
47
|
+
|
|
48
|
+
<script async src="./main.js" type="module"></script>
|
|
49
|
+
|
|
50
|
+
<h1>Exit intent</h1>
|
|
51
|
+
</body>
|
|
52
|
+
</html>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { fake } from "sinon";
|
|
3
|
+
|
|
4
|
+
import { exitIntent } from "../src/exit-intent";
|
|
5
|
+
|
|
6
|
+
it("should update exit_intent session variable", () => {
|
|
7
|
+
window.LiveChatWidget = {
|
|
8
|
+
call: fake(),
|
|
9
|
+
get: fake(() => ({ status: "browsing" })),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const event = new Event("mouseleave");
|
|
13
|
+
|
|
14
|
+
exitIntent();
|
|
15
|
+
|
|
16
|
+
expect(
|
|
17
|
+
window.LiveChatWidget.call.calledWith("update_session_variables", {
|
|
18
|
+
exit_intent: "false",
|
|
19
|
+
})
|
|
20
|
+
).to.be.true;
|
|
21
|
+
document.dispatchEvent(event);
|
|
22
|
+
|
|
23
|
+
expect(
|
|
24
|
+
window.LiveChatWidget.call.calledWith("update_session_variables", {
|
|
25
|
+
exit_intent: "true",
|
|
26
|
+
})
|
|
27
|
+
).to.be.true;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should not update exit_intent session variable when visitor is engaged", () => {
|
|
31
|
+
window.LiveChatWidget = {
|
|
32
|
+
call: fake(),
|
|
33
|
+
get: fake(() => ({ status: "engaged" })),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const event = new Event("mouseleave");
|
|
37
|
+
|
|
38
|
+
exitIntent();
|
|
39
|
+
|
|
40
|
+
expect(
|
|
41
|
+
window.LiveChatWidget.call.calledWith("update_session_variables", {
|
|
42
|
+
exit_intent: "false",
|
|
43
|
+
})
|
|
44
|
+
).to.be.true;
|
|
45
|
+
|
|
46
|
+
document.dispatchEvent(event);
|
|
47
|
+
expect(
|
|
48
|
+
window.LiveChatWidget.call.calledWith("update_session_variables", {
|
|
49
|
+
exit_intent: "true",
|
|
50
|
+
})
|
|
51
|
+
).to.be.false;
|
|
52
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
build: {
|
|
5
|
+
outDir: path.resolve("dist"),
|
|
6
|
+
emptyOutDir: false,
|
|
7
|
+
target: "es2015",
|
|
8
|
+
lib: {
|
|
9
|
+
entry: path.resolve(__dirname, "src/main.js"),
|
|
10
|
+
name: "lcExitIntent",
|
|
11
|
+
fileName: () => `lc-exit-intent.js`,
|
|
12
|
+
formats: ["iife"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default config;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# LiveChat <> Google Analytics tags integration
|
|
2
|
+
|
|
3
|
+
The frontend part of LiveChat & GA tags integration.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Use the following snippet to install the plugin to website _after_ LiveChat and Google Analytics tags.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script
|
|
11
|
+
async
|
|
12
|
+
src="https://cdn.jsdelivr.net/npm/@commversion/libs@version/dist/lc-ga-tags.js"
|
|
13
|
+
></script>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
The script does not need any configuration. Works out of the box.
|
|
19
|
+
To validate it works properly, look for `ga_session` on LiveChat visitor custom data.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<body>
|
|
3
|
+
<!-- Global site tag (gtag.js) - Google Analytics -->
|
|
4
|
+
<script
|
|
5
|
+
async
|
|
6
|
+
src="https://www.googletagmanager.com/gtag/js?id=G-JWDT3GZR82"
|
|
7
|
+
></script>
|
|
8
|
+
<script>
|
|
9
|
+
window.dataLayer = window.dataLayer || [];
|
|
10
|
+
function gtag() {
|
|
11
|
+
dataLayer.push(arguments);
|
|
12
|
+
}
|
|
13
|
+
gtag("js", new Date());
|
|
14
|
+
|
|
15
|
+
gtag("config", "G-JWDT3GZR82");
|
|
16
|
+
</script>
|
|
17
|
+
<!-- Start of LiveChat (www.livechatinc.com) code -->
|
|
18
|
+
<script>
|
|
19
|
+
window.__lc = window.__lc || {};
|
|
20
|
+
window.__lc.license = 10793607;
|
|
21
|
+
(function (n, t, c) {
|
|
22
|
+
function i(n) {
|
|
23
|
+
return e._h ? e._h.apply(null, n) : e._q.push(n);
|
|
24
|
+
}
|
|
25
|
+
var e = {
|
|
26
|
+
_q: [],
|
|
27
|
+
_h: null,
|
|
28
|
+
_v: "2.0",
|
|
29
|
+
on: function () {
|
|
30
|
+
i(["on", c.call(arguments)]);
|
|
31
|
+
},
|
|
32
|
+
once: function () {
|
|
33
|
+
i(["once", c.call(arguments)]);
|
|
34
|
+
},
|
|
35
|
+
off: function () {
|
|
36
|
+
i(["off", c.call(arguments)]);
|
|
37
|
+
},
|
|
38
|
+
get: function () {
|
|
39
|
+
if (!e._h)
|
|
40
|
+
throw new Error(
|
|
41
|
+
"[LiveChatWidget] You can't use getters before load."
|
|
42
|
+
);
|
|
43
|
+
return i(["get", c.call(arguments)]);
|
|
44
|
+
},
|
|
45
|
+
call: function () {
|
|
46
|
+
i(["call", c.call(arguments)]);
|
|
47
|
+
},
|
|
48
|
+
init: function () {
|
|
49
|
+
var n = t.createElement("script");
|
|
50
|
+
(n.async = !0),
|
|
51
|
+
(n.type = "text/javascript"),
|
|
52
|
+
(n.src = "https://cdn.livechatinc.com/tracking.js"),
|
|
53
|
+
t.head.appendChild(n);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
!n.__lc.asyncInit && e.init(),
|
|
57
|
+
(n.LiveChatWidget = n.LiveChatWidget || e);
|
|
58
|
+
})(window, document, [].slice);
|
|
59
|
+
</script>
|
|
60
|
+
<!-- End of LiveChat code -->
|
|
61
|
+
|
|
62
|
+
<script async src="./main.js"></script>
|
|
63
|
+
|
|
64
|
+
<h1>lets see if this works</h1>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { fake } from "sinon";
|
|
3
|
+
import { appendGaSession } from "../src/append-ga-session.js";
|
|
4
|
+
|
|
5
|
+
it("should not engage if no ga exists", () => {
|
|
6
|
+
window.LiveChatWidget = {
|
|
7
|
+
on: fake(),
|
|
8
|
+
call: fake(),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
appendGaSession();
|
|
12
|
+
|
|
13
|
+
expect(window.LiveChatWidget.call.called).to.be.false;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should engage if ga exists", () => {
|
|
17
|
+
window.LiveChatWidget = {
|
|
18
|
+
on: fake(),
|
|
19
|
+
call: fake(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
window.gaGlobal = {
|
|
23
|
+
vid: "some-id",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
appendGaSession();
|
|
27
|
+
|
|
28
|
+
expect(
|
|
29
|
+
window.LiveChatWidget.call.calledWith("update_session_variables", {
|
|
30
|
+
ga_session: "some-id",
|
|
31
|
+
})
|
|
32
|
+
).to.be.true;
|
|
33
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
build: {
|
|
5
|
+
outDir: path.resolve("dist"),
|
|
6
|
+
emptyOutDir: false,
|
|
7
|
+
target: "es2015",
|
|
8
|
+
lib: {
|
|
9
|
+
entry: path.resolve(__dirname, "src/main.js"),
|
|
10
|
+
name: "lcGaTags",
|
|
11
|
+
fileName: () => `lc-ga-tags.js`,
|
|
12
|
+
formats: ["iife"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default config;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# LiveChat Input Error
|
|
2
|
+
|
|
3
|
+
Target visitors that struggle with forms.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Use the following snippet to install the plugin to website _after_ LiveChat tags.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script
|
|
11
|
+
async
|
|
12
|
+
src="https://cdn.jsdelivr.net/npm/@commversion/libs@version/dist/lc-input-error.js"
|
|
13
|
+
></script>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
This script does not need any configuration.
|
|
19
|
+
|
|
20
|
+
When an `invalid` event is emitted from an input element, chat widget will expand and an `input_error` custom variable will be assigned to the visitor.
|
|
21
|
+
|
|
22
|
+
Possible values for `input_error` are `true` and `false`.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<body>
|
|
3
|
+
<link
|
|
4
|
+
rel="stylesheet"
|
|
5
|
+
href="https://cdn.jsdelivr.net/npm/simpledotcss@1.0.5/simple.min.css"
|
|
6
|
+
/>
|
|
7
|
+
<!-- Start of LiveChat (www.livechatinc.com) code -->
|
|
8
|
+
<script>
|
|
9
|
+
window.__lc = window.__lc || {};
|
|
10
|
+
window.__lc.license = 10793607;
|
|
11
|
+
(function (n, t, c) {
|
|
12
|
+
function i(n) {
|
|
13
|
+
return e._h ? e._h.apply(null, n) : e._q.push(n);
|
|
14
|
+
}
|
|
15
|
+
var e = {
|
|
16
|
+
_q: [],
|
|
17
|
+
_h: null,
|
|
18
|
+
_v: "2.0",
|
|
19
|
+
on: function () {
|
|
20
|
+
i(["on", c.call(arguments)]);
|
|
21
|
+
},
|
|
22
|
+
once: function () {
|
|
23
|
+
i(["once", c.call(arguments)]);
|
|
24
|
+
},
|
|
25
|
+
off: function () {
|
|
26
|
+
i(["off", c.call(arguments)]);
|
|
27
|
+
},
|
|
28
|
+
get: function () {
|
|
29
|
+
if (!e._h)
|
|
30
|
+
throw new Error(
|
|
31
|
+
"[LiveChatWidget] You can't use getters before load."
|
|
32
|
+
);
|
|
33
|
+
return i(["get", c.call(arguments)]);
|
|
34
|
+
},
|
|
35
|
+
call: function () {
|
|
36
|
+
i(["call", c.call(arguments)]);
|
|
37
|
+
},
|
|
38
|
+
init: function () {
|
|
39
|
+
var n = t.createElement("script");
|
|
40
|
+
(n.async = !0),
|
|
41
|
+
(n.type = "text/javascript"),
|
|
42
|
+
(n.src = "https://cdn.livechatinc.com/tracking.js"),
|
|
43
|
+
t.head.appendChild(n);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
!n.__lc.asyncInit && e.init(),
|
|
47
|
+
(n.LiveChatWidget = n.LiveChatWidget || e);
|
|
48
|
+
})(window, document, [].slice);
|
|
49
|
+
</script>
|
|
50
|
+
<!-- End of LiveChat code -->
|
|
51
|
+
|
|
52
|
+
<script async src="./main.js" type="module"></script>
|
|
53
|
+
|
|
54
|
+
<h1>Form error</h1>
|
|
55
|
+
|
|
56
|
+
<form>
|
|
57
|
+
<div>
|
|
58
|
+
<label>
|
|
59
|
+
Name
|
|
60
|
+
<input type="text" name="name" required="true" />
|
|
61
|
+
</label>
|
|
62
|
+
</div>
|
|
63
|
+
<div>
|
|
64
|
+
<label>
|
|
65
|
+
Email
|
|
66
|
+
<input type="email" name="email" />
|
|
67
|
+
</label>
|
|
68
|
+
</div>
|
|
69
|
+
<div>
|
|
70
|
+
<button type="submit">Submit</button>
|
|
71
|
+
</div>
|
|
72
|
+
</form>
|
|
73
|
+
</body>
|
|
74
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const handleInputError = () => {
|
|
2
|
+
const { LiveChatWidget } = window;
|
|
3
|
+
|
|
4
|
+
const inputs = document.querySelectorAll("input");
|
|
5
|
+
|
|
6
|
+
inputs.forEach((el) => {
|
|
7
|
+
el.addEventListener("invalid", () => {
|
|
8
|
+
LiveChatWidget.call("update_session_variables", {
|
|
9
|
+
input_error: "true",
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { fake } from "sinon";
|
|
3
|
+
|
|
4
|
+
import { handleInputError } from "../src/input-error.js";
|
|
5
|
+
|
|
6
|
+
it("should update input_error session variable", () => {
|
|
7
|
+
window.LiveChatWidget = {
|
|
8
|
+
call: fake(),
|
|
9
|
+
get: fake(() => ({ status: "browsing" })),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
document.open();
|
|
13
|
+
document.write('<input type="email" required="true"/>');
|
|
14
|
+
document.close();
|
|
15
|
+
|
|
16
|
+
const event = new Event("invalid");
|
|
17
|
+
|
|
18
|
+
handleInputError();
|
|
19
|
+
|
|
20
|
+
document.querySelector("input").dispatchEvent(event);
|
|
21
|
+
|
|
22
|
+
expect(
|
|
23
|
+
window.LiveChatWidget.call.calledWith("update_session_variables", {
|
|
24
|
+
input_error: "true",
|
|
25
|
+
})
|
|
26
|
+
).to.be.true;
|
|
27
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
build: {
|
|
5
|
+
outDir: path.resolve("dist"),
|
|
6
|
+
emptyOutDir: false,
|
|
7
|
+
target: "es2015",
|
|
8
|
+
lib: {
|
|
9
|
+
entry: path.resolve(__dirname, "src/main.js"),
|
|
10
|
+
name: "lcInputError",
|
|
11
|
+
fileName: () => `lc-input-error.js`,
|
|
12
|
+
formats: ["iife"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default config;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# LiveChat Show-Hide
|
|
2
|
+
|
|
3
|
+
Show and hide the chat widget on certain pages.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Use the following snippet to install the plugin to website _after_ tags.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script
|
|
11
|
+
async
|
|
12
|
+
src="https://cdn.jsdelivr.net/npm/@commversion/libs@version/dist/lc-show-hide.js"
|
|
13
|
+
></script>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
The `lc-show-hide` script can be configured in two ways, depending on the requirements.
|
|
19
|
+
|
|
20
|
+
One is to configure the pages the chat should be shown only:
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<script>
|
|
24
|
+
window.commversion = {
|
|
25
|
+
show: "^/show$", // Chat widget will be shown ONLY to /show page
|
|
26
|
+
};
|
|
27
|
+
</script>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Another would be to configure the pages chat will be explicitly hidden:
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<script>
|
|
34
|
+
window.commversion = {
|
|
35
|
+
hide: "^/hide$", // Chat widget will be shown everywhere EXCEPT /hide page
|
|
36
|
+
};
|
|
37
|
+
</script>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Mind that the page configuration is a regular expression. You can use (regexer)[https://regexr.com/] to try out regular expressions.
|
|
41
|
+
|
|
42
|
+
Note: The chat widget will be **shown** regardless configuration when:
|
|
43
|
+
|
|
44
|
+
- A visitor has an active conversation.
|
|
45
|
+
- A visitor has been previously engaged by a greeting.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<body>
|
|
3
|
+
<!-- Start of LiveChat (www.livechatinc.com) code -->
|
|
4
|
+
<script>
|
|
5
|
+
window.__lc = window.__lc || {};
|
|
6
|
+
window.__lc.license = 10793607;
|
|
7
|
+
(function (n, t, c) {
|
|
8
|
+
function i(n) {
|
|
9
|
+
return e._h ? e._h.apply(null, n) : e._q.push(n);
|
|
10
|
+
}
|
|
11
|
+
var e = {
|
|
12
|
+
_q: [],
|
|
13
|
+
_h: null,
|
|
14
|
+
_v: "2.0",
|
|
15
|
+
on: function () {
|
|
16
|
+
i(["on", c.call(arguments)]);
|
|
17
|
+
},
|
|
18
|
+
once: function () {
|
|
19
|
+
i(["once", c.call(arguments)]);
|
|
20
|
+
},
|
|
21
|
+
off: function () {
|
|
22
|
+
i(["off", c.call(arguments)]);
|
|
23
|
+
},
|
|
24
|
+
get: function () {
|
|
25
|
+
if (!e._h)
|
|
26
|
+
throw new Error(
|
|
27
|
+
"[LiveChatWidget] You can't use getters before load."
|
|
28
|
+
);
|
|
29
|
+
return i(["get", c.call(arguments)]);
|
|
30
|
+
},
|
|
31
|
+
call: function () {
|
|
32
|
+
i(["call", c.call(arguments)]);
|
|
33
|
+
},
|
|
34
|
+
init: function () {
|
|
35
|
+
var n = t.createElement("script");
|
|
36
|
+
(n.async = !0),
|
|
37
|
+
(n.type = "text/javascript"),
|
|
38
|
+
(n.src = "https://cdn.livechatinc.com/tracking.js"),
|
|
39
|
+
t.head.appendChild(n);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
!n.__lc.asyncInit && e.init(),
|
|
43
|
+
(n.LiveChatWidget = n.LiveChatWidget || e);
|
|
44
|
+
})(window, document, [].slice);
|
|
45
|
+
</script>
|
|
46
|
+
<!-- End of LiveChat code -->
|
|
47
|
+
|
|
48
|
+
<script async src="./main.js" type="module"></script>
|
|
49
|
+
<script>
|
|
50
|
+
window.commversion = {
|
|
51
|
+
// show: "^/show$",
|
|
52
|
+
hide: "^/hide$",
|
|
53
|
+
};
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<h1>show-hide</h1>
|
|
57
|
+
</body>
|
|
58
|
+
</html>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const showPredicate = (pagesRegExp, currentUrl) => {
|
|
2
|
+
const shouldHide = !pagesRegExp.test(currentUrl);
|
|
3
|
+
|
|
4
|
+
return shouldHide;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const hidePredicate = (pagesRegExp, currentUrl) => {
|
|
8
|
+
const shouldHide = pagesRegExp.test(currentUrl);
|
|
9
|
+
|
|
10
|
+
return shouldHide;
|
|
11
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { hidePredicate, showPredicate } from "./predicate-functions.js";
|
|
2
|
+
|
|
3
|
+
const hideableStatuses = ["browsing"];
|
|
4
|
+
|
|
5
|
+
const getPlugin = (configuration) => {
|
|
6
|
+
if (configuration.show && configuration.hide) {
|
|
7
|
+
return {
|
|
8
|
+
predicateFn: () =>
|
|
9
|
+
console.error(
|
|
10
|
+
"Cannot set both show and hide configuration. Please choose one."
|
|
11
|
+
),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (configuration.show) {
|
|
16
|
+
return {
|
|
17
|
+
predicateFn: showPredicate,
|
|
18
|
+
pluginConfiguration: configuration.show,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (configuration.hide) {
|
|
23
|
+
return {
|
|
24
|
+
predicateFn: hidePredicate,
|
|
25
|
+
pluginConfiguration: configuration.hide,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
predicateFn: () => console.error("No configuration for show/hide script."),
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const showHide =
|
|
35
|
+
(configuration) =>
|
|
36
|
+
({ customerData }) => {
|
|
37
|
+
const { LiveChatWidget } = window;
|
|
38
|
+
const currentUrl = window.location.pathname;
|
|
39
|
+
|
|
40
|
+
const { predicateFn, pluginConfiguration } = getPlugin(configuration);
|
|
41
|
+
|
|
42
|
+
const shouldHide =
|
|
43
|
+
predicateFn(new RegExp(pluginConfiguration), currentUrl) &&
|
|
44
|
+
hideableStatuses.includes(customerData.status);
|
|
45
|
+
|
|
46
|
+
if (shouldHide) {
|
|
47
|
+
LiveChatWidget.call("hide");
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { fake } from "sinon";
|
|
3
|
+
import { hidePredicate, showPredicate } from "../src/predicate-functions.js";
|
|
4
|
+
|
|
5
|
+
describe("hidePredicate", () => {
|
|
6
|
+
it("should return true", () => {
|
|
7
|
+
const shouldHide = hidePredicate(new RegExp("^/$"), "/");
|
|
8
|
+
|
|
9
|
+
expect(shouldHide).to.be.true;
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should return false", () => {
|
|
13
|
+
const shouldHide = hidePredicate(new RegExp("^/$"), "/test");
|
|
14
|
+
|
|
15
|
+
expect(shouldHide).to.be.false;
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("showPredicate", () => {
|
|
20
|
+
it("should return false", () => {
|
|
21
|
+
const shouldHide = showPredicate(new RegExp("^/$"), "/");
|
|
22
|
+
|
|
23
|
+
expect(shouldHide).to.be.false;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should return reue", () => {
|
|
27
|
+
const shouldHide = showPredicate(new RegExp("^/$"), "/test");
|
|
28
|
+
|
|
29
|
+
expect(shouldHide).to.be.true;
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
build: {
|
|
5
|
+
outDir: path.resolve("dist"),
|
|
6
|
+
emptyOutDir: false,
|
|
7
|
+
target: "es2015",
|
|
8
|
+
lib: {
|
|
9
|
+
entry: path.resolve(__dirname, "src/main.js"),
|
|
10
|
+
name: "lcShowHide",
|
|
11
|
+
fileName: () => "lc-show-hide.js",
|
|
12
|
+
formats: ["iife"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default config;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Schedule event
|
|
2
|
+
|
|
3
|
+
A plugin to help trigger events on weekly basis.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Use the following snippet to install the plugin to website.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<script
|
|
11
|
+
async
|
|
12
|
+
src="https://cdn.jsdelivr.net/npm/@commversion/libs@version/dist/schedule-event.js"
|
|
13
|
+
></script>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
window.commversion = window.commversion || {};
|
|
17
|
+
|
|
18
|
+
window.commversion.timezone = "Asia/Kolkata";
|
|
19
|
+
window.commversion.schedule = [
|
|
20
|
+
{
|
|
21
|
+
from: [0, 0, 0],
|
|
22
|
+
to: [1, 23, 59],
|
|
23
|
+
callback: () => alert("triggers sunday & monday"),
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
from: [2, 0, 0],
|
|
27
|
+
to: [3, 23, 59],
|
|
28
|
+
callback: () => alert("triggers tuesday & wednesday"),
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
The script needs to set some configuration into `window.commversion`. It needs to define the schedule plan for the triggers and the website's timezone.
|
|
37
|
+
|
|
38
|
+
### Timezones
|
|
39
|
+
|
|
40
|
+
All IANA timezones are supported but not local idioms for non-western date-times.
|
|
41
|
+
Please find the list of all timezones at this [Wikipedia article](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
|
|
42
|
+
|
|
43
|
+
### Rules syntax
|
|
44
|
+
|
|
45
|
+
A special set of rules are used to define the schedule. Each rule has to hold a `from` property (consider this the starting point), a `to` property (ending point) and a `callback` function to trigger when active.
|
|
46
|
+
|
|
47
|
+
`from` and `to` are defined like this:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
[1, 13, 30]
|
|
51
|
+
│ │ │
|
|
52
|
+
│ │ └─────► minute of the hour
|
|
53
|
+
│ └─────────► hour of the day (24hrs)
|
|
54
|
+
└────────────► day of the week (Sunday is 0)
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
In case multiple rules are overriding each other's schedule, only the first will be considered as active.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<body>
|
|
3
|
+
<script async src="./main.js"></script>
|
|
4
|
+
<script>
|
|
5
|
+
window.commversion = {
|
|
6
|
+
schedule: [
|
|
7
|
+
{ from: [0, 0, 0], to: [2, 23, 59], callback: () => alert("runs") },
|
|
8
|
+
],
|
|
9
|
+
timezone: "Asia/Kolkata",
|
|
10
|
+
};
|
|
11
|
+
</script>
|
|
12
|
+
<h1>lets see if this works</h1>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import scheduleEvent from "./schedule-event.js";
|
|
2
|
+
|
|
3
|
+
window.commversion = window.commversion || {};
|
|
4
|
+
|
|
5
|
+
const { schedule, timezone } = window.commversion;
|
|
6
|
+
|
|
7
|
+
[schedule, timezone].forEach((p) => {
|
|
8
|
+
if (typeof p !== "undefined") return;
|
|
9
|
+
|
|
10
|
+
throw new Error("Invalid configuration");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
scheduleEvent(schedule, timezone);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const noop = () => {};
|
|
2
|
+
const getScore = (day, hour, minute) => day * 1440 + hour * 60 + minute;
|
|
3
|
+
|
|
4
|
+
export default (schedule, now) => {
|
|
5
|
+
const action = schedule.reverse().reduce((acc, { from, to, callback }) => {
|
|
6
|
+
const scoreFrom = getScore(from[0], from[1], from[2]);
|
|
7
|
+
const scoreTo = getScore(to[0], to[1], to[2]);
|
|
8
|
+
const scoreNow = getScore(now[0], now[1], now[2]);
|
|
9
|
+
|
|
10
|
+
const isActive = scoreFrom <= scoreNow && scoreNow < scoreTo;
|
|
11
|
+
|
|
12
|
+
return isActive ? callback : acc;
|
|
13
|
+
}, noop);
|
|
14
|
+
|
|
15
|
+
return action;
|
|
16
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import spacetime from "spacetime";
|
|
2
|
+
import parseSchedule from "./parse-schedule.js";
|
|
3
|
+
|
|
4
|
+
const scheduleEvent = async (schedule, timezone) => {
|
|
5
|
+
const now = spacetime(new Date(), timezone, {
|
|
6
|
+
weekStart: 0,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const callback = parseSchedule(schedule, [
|
|
10
|
+
now.day(),
|
|
11
|
+
now.hour(),
|
|
12
|
+
now.minute(),
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
await callback();
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default scheduleEvent;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { fake } from "sinon";
|
|
3
|
+
import parseSchedule from "../src/parse-schedule.js";
|
|
4
|
+
|
|
5
|
+
it("should call callback when is active", () => {
|
|
6
|
+
const callback = fake();
|
|
7
|
+
const wedMorning = [3, 10, 0];
|
|
8
|
+
|
|
9
|
+
const schedule = [{ from: [3, 10, 0], to: [3, 18, 0], callback }];
|
|
10
|
+
|
|
11
|
+
expect(parseSchedule(schedule, wedMorning)).to.equal(callback);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should not call callback when is not active", () => {
|
|
15
|
+
const callback = fake();
|
|
16
|
+
const wedMorning = [3, 10, 0];
|
|
17
|
+
|
|
18
|
+
const schedule = [{ from: [4, 10, 0], to: [4, 18, 0], callback }];
|
|
19
|
+
|
|
20
|
+
expect(parseSchedule(schedule, wedMorning)).to.not.equal(callback);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should support multiple cases", () => {
|
|
24
|
+
const callback = fake();
|
|
25
|
+
const callbackB = fake();
|
|
26
|
+
const wedMorning = [3, 10, 0];
|
|
27
|
+
|
|
28
|
+
const schedule = [
|
|
29
|
+
{ from: [0, 10, 0], to: [0, 18, 0], callback },
|
|
30
|
+
{ from: [1, 10, 0], to: [1, 18, 0], callback },
|
|
31
|
+
{ from: [2, 10, 0], to: [2, 18, 0], callback },
|
|
32
|
+
{ from: [3, 10, 0], to: [3, 18, 0], callback: callbackB },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
expect(parseSchedule(schedule, wedMorning)).to.equal(callbackB);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("in case of overlapping ranges, the first one is executed", () => {
|
|
39
|
+
const callback = fake();
|
|
40
|
+
const callbackB = fake();
|
|
41
|
+
const wedMorning = [3, 11, 0];
|
|
42
|
+
|
|
43
|
+
const schedule = [
|
|
44
|
+
{ from: [3, 10, 30], to: [3, 18, 0], callback: callbackB },
|
|
45
|
+
{ from: [3, 10, 30], to: [3, 18, 0], callback },
|
|
46
|
+
{ from: [3, 10, 30], to: [3, 18, 0], callback },
|
|
47
|
+
{ from: [3, 10, 30], to: [3, 18, 0], callback },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
expect(parseSchedule(schedule, wedMorning)).to.equal(callbackB);
|
|
51
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { fake } from "sinon";
|
|
3
|
+
import scheduleEvent from "../src/schedule-event.js";
|
|
4
|
+
|
|
5
|
+
it("should call the callback", async () => {
|
|
6
|
+
const callback = fake();
|
|
7
|
+
|
|
8
|
+
const schedule = [{ from: [0, 0, 0], to: [6, 23, 59], callback }];
|
|
9
|
+
|
|
10
|
+
await scheduleEvent(schedule, "Asia/Kolkata");
|
|
11
|
+
|
|
12
|
+
expect(callback.called).to.be.true;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should not call the callback", async () => {
|
|
16
|
+
const callback = fake();
|
|
17
|
+
|
|
18
|
+
const schedule = [{ from: [0, 0, 0], to: [0, 0, 0], callback }];
|
|
19
|
+
|
|
20
|
+
await scheduleEvent(schedule, "Asia/Kolkata");
|
|
21
|
+
|
|
22
|
+
expect(callback.called).not.to.be.true;
|
|
23
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
build: {
|
|
5
|
+
outDir: path.resolve("dist"),
|
|
6
|
+
emptyOutDir: false,
|
|
7
|
+
target: "es2015",
|
|
8
|
+
lib: {
|
|
9
|
+
entry: path.resolve(__dirname, "src/main.js"),
|
|
10
|
+
name: "scheduleEvent",
|
|
11
|
+
fileName: () => `schedule-event.js`,
|
|
12
|
+
formats: ["iife"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default config;
|