@hashtagcms/web-sdk 1.0.0
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 +71 -0
- package/docs/01-architecture.md +27 -0
- package/docs/02-bootstrap.md +32 -0
- package/docs/03-components.md +62 -0
- package/docs/04-integration.md +39 -0
- package/package.json +19 -0
- package/src/bootstrap.js +11 -0
- package/src/components/newsletter.js +75 -0
- package/src/helpers/common.js +18 -0
- package/src/index.js +11 -0
- package/src/utils/analytics.js +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 HashtagCMS
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @hashtagcms/web-sdk
|
|
2
|
+
|
|
3
|
+
> Core JavaScript SDK for the HashtagCMS ecosystem
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
This package contains the core JavaScript logic and components for HashtagCMS, providing shared functionality that is used across both **Blade/PHP** (`@hashtagcms/web-ui-kit`) and **Java** (`@hashtagcms/theme-java`) theme ecosystems.
|
|
8
|
+
|
|
9
|
+
## 📚 Documentation
|
|
10
|
+
|
|
11
|
+
For more detailed information, check the following guides:
|
|
12
|
+
|
|
13
|
+
- [Architecture & Design](./docs/01-architecture.md)
|
|
14
|
+
- [Bootstrap & Global Config](./docs/02-bootstrap.md)
|
|
15
|
+
- [Component API Reference](./docs/03-components.md)
|
|
16
|
+
- [Integrating with Themes (PHP/Java)](./docs/04-integration.md)
|
|
17
|
+
|
|
18
|
+
## ✨ Features
|
|
19
|
+
|
|
20
|
+
- 🛠️ **Core Components** - Shared logic like Configuration forms and Analytics tracking
|
|
21
|
+
- 🔧 **Configurable** - Manage application settings with `AppConfig`
|
|
22
|
+
- 🌐 **Standardized Requests** - Automatic CSRF token handling and Axios configuration
|
|
23
|
+
- 📦 **Framework Agnostic** - Vanilla JavaScript logic that works anywhere
|
|
24
|
+
- 🚀 **Lightweight** - Minimized footprint for high-performance builds
|
|
25
|
+
|
|
26
|
+
## 📦 Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @hashtagcms/web-sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 🚀 Quick Start
|
|
33
|
+
|
|
34
|
+
### Basic Usage
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
import { Analytics, Subscribe, AppConfig } from "@hashtagcms/web-sdk";
|
|
38
|
+
|
|
39
|
+
// Initialize Components
|
|
40
|
+
const subscribe = new Subscribe();
|
|
41
|
+
const analytics = new Analytics();
|
|
42
|
+
const config = new AppConfig({
|
|
43
|
+
media: { http_path: "https://cdn.example.com" }
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Use analytics
|
|
47
|
+
analytics.trackPageView('/home');
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 🛠️ API Reference
|
|
51
|
+
|
|
52
|
+
### `Subscribe`
|
|
53
|
+
Handles newsletter or contact form configuration.
|
|
54
|
+
- `init()`: Automatically finds form elements and attaches listeners.
|
|
55
|
+
- `subscribeNow()`: Programmatically triggers a configuration request.
|
|
56
|
+
|
|
57
|
+
### `Analytics`
|
|
58
|
+
Standardized tracking for HashtagCMS.
|
|
59
|
+
- `init(data)`: Initializes tracking with initial data.
|
|
60
|
+
- `trackPageView(url)`: Tracks a page view event.
|
|
61
|
+
- `trackEventView(category, action, value)`: Tracks a custom interaction.
|
|
62
|
+
|
|
63
|
+
### `AppConfig`
|
|
64
|
+
A helper class to manage CMS configuration.
|
|
65
|
+
- `setConfigData(data)`: Update the current configuration.
|
|
66
|
+
- `getValue(key, defaultVal)`: Safely retrieve configuration values.
|
|
67
|
+
- `getMedia(path)`: Get the full CDN/Server path for a media asset.
|
|
68
|
+
|
|
69
|
+
## 📄 License
|
|
70
|
+
|
|
71
|
+
[MIT](LICENSE) © HashtagCMS
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Web SDK Architecture
|
|
2
|
+
|
|
3
|
+
The `@hashtagcms/web-sdk` is designed as a lightweight, framework-agnostic collection of utilities and components used by the HashtagCMS ecosystem.
|
|
4
|
+
|
|
5
|
+
## 📁 Project Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
@hashtagcms/web-sdk/
|
|
9
|
+
├── src/
|
|
10
|
+
│ ├── bootstrap.js # Global initialization (Axios, CSRF)
|
|
11
|
+
│ ├── index.js # Main entry point (Exports)
|
|
12
|
+
│ ├── components/ # UI-related logic
|
|
13
|
+
│ │ └── subscribe.js # Configuration form handler
|
|
14
|
+
│ ├── helpers/ # Shared helpers
|
|
15
|
+
│ │ └── common.js # AppConfig and utilities
|
|
16
|
+
│ └── utils/ # General utilities
|
|
17
|
+
│ └── analytics.js # Tracking logic
|
|
18
|
+
├── package.json
|
|
19
|
+
└── README.md
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 🏗️ Design Principles
|
|
23
|
+
|
|
24
|
+
1. **Framework Agnostic**: No dependency on React, Vue, or Angular. Uses vanilla JavaScript to ensure compatibility with any frontend environment (Blade templates, Thymeleaf, etc.).
|
|
25
|
+
2. **Minimal Dependencies**: Keeps the bundle size small. Currently only depends on `axios` for HTTP requests.
|
|
26
|
+
3. **Singleton Compatibility**: Designed to be initialized once per page load to manage global state like configuration and tracking.
|
|
27
|
+
4. **Data-Attr Driven**: Components are designed to find their target elements using HTML5 `data-` attributes, reducing the need for explicit DOM passing in most cases.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Bootstrap and Initialization
|
|
2
|
+
|
|
3
|
+
The `bootstrap.js` file handles the global setup required for HashtagCMS to communicate with the backend.
|
|
4
|
+
|
|
5
|
+
## 🛠️ Automated Setup
|
|
6
|
+
|
|
7
|
+
When you import the SDK, it automatically performs several actions:
|
|
8
|
+
|
|
9
|
+
1. **Axios Configuration**:
|
|
10
|
+
- Sets the `X-Requested-With: XMLHttpRequest` header.
|
|
11
|
+
- Enables `withCredentials` for cross-site cookie handling.
|
|
12
|
+
2. **CSRF Protection**:
|
|
13
|
+
- Automatically looks for a `<meta name="csrf-token" content="...">` tag in the document head.
|
|
14
|
+
- Sets the `X-CSRF-TOKEN` header for all Axios requests.
|
|
15
|
+
- Sets the `Authorization: Bearer <token>` header for API compatibility.
|
|
16
|
+
|
|
17
|
+
## 🚀 Manual Usage
|
|
18
|
+
|
|
19
|
+
In most cases, you don't need to call bootstrap manually. It is executed as a side-effect when you import the main SDK index or components.
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// This will trigger bootstrap.js
|
|
23
|
+
import { Subscribe } from '@hashtagcms/web-sdk';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 🌐 Global Axios
|
|
27
|
+
|
|
28
|
+
The SDK exposes `axios` to the global `window` object for convenience in legacy scripts or simple inline templates:
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
window.axios.get('/api/endpoint').then(...);
|
|
32
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Component Documentation
|
|
2
|
+
|
|
3
|
+
## `Newsletter`
|
|
4
|
+
|
|
5
|
+
Handles newsletter and subscription forms using a standardized HTML structure.
|
|
6
|
+
*Note: Also exported as `Subscribe` for backward compatibility.*
|
|
7
|
+
|
|
8
|
+
### Usage
|
|
9
|
+
```javascript
|
|
10
|
+
import { Newsletter } from '@hashtagcms/web-sdk';
|
|
11
|
+
const newsletter = new Newsletter();
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### HTML Requirements
|
|
15
|
+
The component automatically detects if it should use the new `newsletter` or legacy `subscribe` selectors.
|
|
16
|
+
|
|
17
|
+
**Primary (New):**
|
|
18
|
+
- `form[data-form='newsletter-form']`
|
|
19
|
+
- `span[data-class='newsletter-message']`
|
|
20
|
+
- `div[data-message-holder='newsletter-message-holder']`
|
|
21
|
+
- `span[data-class='newsletter-close']`
|
|
22
|
+
|
|
23
|
+
**Legacy (Fallback):**
|
|
24
|
+
- `form[data-form='subscribe-form']`
|
|
25
|
+
- `span[data-class='subscribe-message']`
|
|
26
|
+
- `div[data-message-holder='subscribe-message-holder']`
|
|
27
|
+
- `span[data-class='subscribe-close']`
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## `Analytics`
|
|
32
|
+
|
|
33
|
+
Provides a unified interface for tracking page views and custom events.
|
|
34
|
+
|
|
35
|
+
### Methods
|
|
36
|
+
- `init(data)`: Optional initialization with default data.
|
|
37
|
+
- `trackPageView(url)`: Sends a page view event to the CMS and Google Analytics (if detected).
|
|
38
|
+
- `trackEventView(category, action, value)`: Tracks custom interactions.
|
|
39
|
+
|
|
40
|
+
### Example
|
|
41
|
+
```javascript
|
|
42
|
+
const analytics = new Analytics();
|
|
43
|
+
analytics.trackPageView(window.location.pathname);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## `AppConfig`
|
|
49
|
+
|
|
50
|
+
Manages configuration data provided by the CMS backend.
|
|
51
|
+
|
|
52
|
+
### Methods
|
|
53
|
+
- `constructor(initialData)`
|
|
54
|
+
- `setConfigData(data)`: Replace the current configuration.
|
|
55
|
+
- `getValue(key, defaultVal)`: Safely retrieve a value (e.g., `getValue('site_name', 'Default Name')`).
|
|
56
|
+
- `getMedia(path)`: Constructs a full URL for a media asset using the configured media HTTP path.
|
|
57
|
+
|
|
58
|
+
### Example
|
|
59
|
+
```javascript
|
|
60
|
+
const config = new AppConfig(window.cmsConfig);
|
|
61
|
+
const logoUrl = config.getMedia('logo.png');
|
|
62
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Theme Integration Guide
|
|
2
|
+
|
|
3
|
+
The Web SDK isdesigned to be the functional core for any HashtagCMS theme, regardless of the rendering engine.
|
|
4
|
+
|
|
5
|
+
## 🐘 PHP/Blade Integration (`@hashtagcms/web-ui-kit`)
|
|
6
|
+
|
|
7
|
+
In a Laravel environment, themes typically use standard bundlers like Webpack or Vite.
|
|
8
|
+
|
|
9
|
+
1. Install the SDK: `npm install @hashtagcms/web-sdk`
|
|
10
|
+
2. Import in your `app.js`:
|
|
11
|
+
```javascript
|
|
12
|
+
import { Subscribe, Analytics, AppConfig } from '@hashtagcms/web-sdk';
|
|
13
|
+
|
|
14
|
+
window.HashtagCms = {
|
|
15
|
+
Subscribe: new Subscribe(),
|
|
16
|
+
Analytics: new Analytics(),
|
|
17
|
+
AppConfig: new AppConfig(window.cmsData)
|
|
18
|
+
};
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## ☕ Java/Thymeleaf Integration (`@hashtagcms/theme-java`)
|
|
22
|
+
|
|
23
|
+
In the Java ecosystem, the SDK can be integrated via NPM (if using a modern JS build pipeline) or by including the bundled distribution in your templates.
|
|
24
|
+
|
|
25
|
+
1. Ensure the `csrf-token` meta tag is populated by the Java backend.
|
|
26
|
+
2. Initialize the SDK in your main template:
|
|
27
|
+
```html
|
|
28
|
+
<script th:inline="javascript">
|
|
29
|
+
/* Initialize config from server-side model */
|
|
30
|
+
const config = new HashtagCms.AppConfig([[${cmsConfig}]]);
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 🏗️ Future Platforms
|
|
35
|
+
|
|
36
|
+
Because the SDK is vanilla Javascript and focused on API interactions, it can be easily ported to:
|
|
37
|
+
- Mobile web views.
|
|
38
|
+
- Headless CMS frontends (Next.js, Nuxt.js).
|
|
39
|
+
- Static site generators.
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hashtagcms/web-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Core SDK for HashtagCMS Frontend",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"build": "webpack --mode production"
|
|
9
|
+
},
|
|
10
|
+
"author": "HashtagCMS",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"axios": "^1.8.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"webpack": "^5.104.1",
|
|
17
|
+
"webpack-cli": "^6.0.1"
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/bootstrap.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
|
3
|
+
let token = document.head.querySelector('meta[name="csrf-token"]');
|
|
4
|
+
if (token) {
|
|
5
|
+
axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
|
|
6
|
+
axios.defaults.headers.common['Authorization'] = 'Bearer '+token.content;
|
|
7
|
+
axios.defaults.withCredentials = true;
|
|
8
|
+
} else {
|
|
9
|
+
// console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
|
|
10
|
+
}
|
|
11
|
+
window.axios = axios;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export default class Newsletter {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.elements = {
|
|
4
|
+
close: "span[data-class='newsletter-close']",
|
|
5
|
+
message: "span[data-class='newsletter-message']",
|
|
6
|
+
form: "form[data-form='newsletter-form']",
|
|
7
|
+
messageHolder: "div[data-message-holder='newsletter-message-holder']"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// Backward compatibility: Use 'subscribe' selectors if 'newsletter' form is not found
|
|
11
|
+
if (!document.querySelector(this.elements.form)) {
|
|
12
|
+
this.elements = {
|
|
13
|
+
close: "span[data-class='subscribe-close']",
|
|
14
|
+
message: "span[data-class='subscribe-message']",
|
|
15
|
+
form: "form[data-form='subscribe-form']",
|
|
16
|
+
messageHolder: "div[data-message-holder='subscribe-message-holder']"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
this.init();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
init() {
|
|
24
|
+
|
|
25
|
+
if (document.querySelector(this.elements.close)) {
|
|
26
|
+
document.querySelector(this.elements.close).addEventListener('click', (ele) => {
|
|
27
|
+
document.querySelector(this.elements.messageHolder).style.display = "none";
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
newsletterNow() {
|
|
33
|
+
let showMessage = function (message) {
|
|
34
|
+
document.querySelector($this.elements.message).innerText = message;
|
|
35
|
+
}
|
|
36
|
+
let $this = this;
|
|
37
|
+
let afterSave = function (data) {
|
|
38
|
+
console.log("data ", data);
|
|
39
|
+
document.querySelector($this.elements.messageHolder).style.display = "";
|
|
40
|
+
if (data.success == true) {
|
|
41
|
+
showMessage(data.message);
|
|
42
|
+
document.querySelector($this.elements.message).innerText = data.message;
|
|
43
|
+
document.querySelector($this.elements.form + " input[type='email']").value = '';
|
|
44
|
+
document.querySelector($this.elements.message).classList.remove("text-danger");
|
|
45
|
+
document.querySelector($this.elements.message).classList.add("text-success");
|
|
46
|
+
} else {
|
|
47
|
+
let errorMsg = (data.message && data.message.email && data.message.email[0]) ? data.message.email[0] : (data.message || "There is some error.");
|
|
48
|
+
showMessage(errorMsg);
|
|
49
|
+
document.querySelector($this.elements.message).classList.remove("text-success");
|
|
50
|
+
document.querySelector($this.elements.message).classList.add("text-danger");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let email = document.querySelector(this.elements.form + " input[type='email']");
|
|
55
|
+
let url = "/common/newsletter";
|
|
56
|
+
let data = { email: email.value };
|
|
57
|
+
axios.post(url, data)
|
|
58
|
+
.then(response => {
|
|
59
|
+
afterSave(response.data);
|
|
60
|
+
}).catch((error) => {
|
|
61
|
+
afterSave(error.response.data);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Alias for newsletterNow
|
|
69
|
+
* @deprecated
|
|
70
|
+
*/
|
|
71
|
+
subscribeNow() {
|
|
72
|
+
return this.newsletterNow();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class AppConfig {
|
|
2
|
+
constructor(data) {
|
|
3
|
+
this.configData = data;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
setConfigData(data) {
|
|
7
|
+
this.configData = data;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
getValue(key, defaultVal) {
|
|
11
|
+
return this.configData[key] || defaultVal;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getMedia(path) {
|
|
15
|
+
let media = this.getValue("media");
|
|
16
|
+
return media.http_path+"/"+path;
|
|
17
|
+
}
|
|
18
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import './bootstrap';
|
|
2
|
+
import Newsletter from './components/newsletter';
|
|
3
|
+
import Analytics from './utils/analytics';
|
|
4
|
+
import { AppConfig } from './helpers/common';
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
Newsletter,
|
|
8
|
+
Newsletter as Subscribe, // Alias for backward compatibility
|
|
9
|
+
Analytics,
|
|
10
|
+
AppConfig
|
|
11
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export default class Analytics {
|
|
2
|
+
|
|
3
|
+
constructor() {
|
|
4
|
+
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
init(data) {
|
|
8
|
+
this.readCounter(data);
|
|
9
|
+
}
|
|
10
|
+
readCounter(data) {
|
|
11
|
+
|
|
12
|
+
this.submit("post", "/analytics/publish", data);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Submit request.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} requestType
|
|
19
|
+
* @param {string} url
|
|
20
|
+
* @param data
|
|
21
|
+
*/
|
|
22
|
+
submit(requestType, url, data) {
|
|
23
|
+
/*data = new Blob([JSON.stringify(data)], {type : 'application/json'});
|
|
24
|
+
data.csrfToken = window.Laravel.csrfToken;
|
|
25
|
+
console.log("data",data);
|
|
26
|
+
navigator.sendBeacon(url, data);*/
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
axios[requestType](url, data)
|
|
29
|
+
.then(response => {
|
|
30
|
+
resolve(response.data);
|
|
31
|
+
}).catch(error => {
|
|
32
|
+
reject(error.response.data);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
trackEventView (category, action ,value, cb) {
|
|
38
|
+
try {
|
|
39
|
+
//very very old ga
|
|
40
|
+
_gaq.push(['_trackEvent', category, action, value]);
|
|
41
|
+
} catch(e) {
|
|
42
|
+
}
|
|
43
|
+
if ( typeof ga != "undefined") {
|
|
44
|
+
try {
|
|
45
|
+
ga('send', {
|
|
46
|
+
hitType : 'event',
|
|
47
|
+
eventCategory : category,
|
|
48
|
+
eventAction : action,
|
|
49
|
+
eventLabel : value
|
|
50
|
+
});
|
|
51
|
+
} catch(e) {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (cb) {
|
|
55
|
+
cb.apply(this, arguments);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Track Page view
|
|
61
|
+
* @param value
|
|
62
|
+
* @param cb
|
|
63
|
+
*/
|
|
64
|
+
trackPageView (value, cb) {
|
|
65
|
+
try {
|
|
66
|
+
//Very very old ga
|
|
67
|
+
_gaq.push(['_trackPageview', value]);
|
|
68
|
+
} catch(e) {
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if ( typeof ga != "undefined") {
|
|
72
|
+
try {
|
|
73
|
+
ga('send',
|
|
74
|
+
{hitType: 'pageview',
|
|
75
|
+
page: value
|
|
76
|
+
});
|
|
77
|
+
} catch(e) {}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (cb) {
|
|
81
|
+
cb.apply(this, arguments);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|