@hashtagcms/admin-ui-kit 1.0.6
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 +83 -0
- package/dist/admin-ui-kit.min.css +14 -0
- package/dist/admin-ui-kit.min.js +2 -0
- package/dist/admin-ui-kit.min.js.LICENSE.txt +175 -0
- package/package.json +53 -0
- package/packages/components/README.md +92 -0
- package/packages/components/package.json +28 -0
- package/packages/components/src/action-bar.vue +237 -0
- package/packages/components/src/category-platform.vue +97 -0
- package/packages/components/src/category-settings.vue +815 -0
- package/packages/components/src/cms-module-dropdown.vue +78 -0
- package/packages/components/src/downlods.vue +21 -0
- package/packages/components/src/file-uploader.vue +188 -0
- package/packages/components/src/frontend-module-creator.vue +599 -0
- package/packages/components/src/global-site-button.vue +94 -0
- package/packages/components/src/homepage.vue +1087 -0
- package/packages/components/src/html-slot.vue +23 -0
- package/packages/components/src/image-gallery.vue +144 -0
- package/packages/components/src/index.js +53 -0
- package/packages/components/src/info-boxes.vue +68 -0
- package/packages/components/src/info-popup.vue +121 -0
- package/packages/components/src/language-button.vue +80 -0
- package/packages/components/src/language-copier.vue +177 -0
- package/packages/components/src/left-nav.vue +159 -0
- package/packages/components/src/library/copy-paste.vue +186 -0
- package/packages/components/src/library/info-box.vue +102 -0
- package/packages/components/src/library/left-menu-show-hide.vue +47 -0
- package/packages/components/src/library/loader.vue +141 -0
- package/packages/components/src/library/modal-box.vue +136 -0
- package/packages/components/src/library/split-button.vue +127 -0
- package/packages/components/src/library/timer-button.vue +43 -0
- package/packages/components/src/library/toast-box.vue +53 -0
- package/packages/components/src/menu-sorter.vue +265 -0
- package/packages/components/src/module-creator.vue +650 -0
- package/packages/components/src/module-permission.vue +334 -0
- package/packages/components/src/pagination.vue +125 -0
- package/packages/components/src/platform-button.vue +118 -0
- package/packages/components/src/search-bar.vue +144 -0
- package/packages/components/src/site-button.vue +42 -0
- package/packages/components/src/site-cloner.vue +150 -0
- package/packages/components/src/sitewise-copier.vue +234 -0
- package/packages/components/src/sitewise-data.vue +347 -0
- package/packages/components/src/sorter.vue +239 -0
- package/packages/components/src/tabular-view.vue +824 -0
- package/packages/components/src/title-bar.vue +76 -0
- package/packages/components/src/top-nav.vue +96 -0
- package/packages/helpers/README.md +88 -0
- package/packages/helpers/package.json +20 -0
- package/packages/helpers/src/admin-config.js +9 -0
- package/packages/helpers/src/common.js +89 -0
- package/packages/helpers/src/dashboard.js +16 -0
- package/packages/helpers/src/editor.js +163 -0
- package/packages/helpers/src/error-message-handler.js +50 -0
- package/packages/helpers/src/event-bus.js +4 -0
- package/packages/helpers/src/form.js +4 -0
- package/packages/helpers/src/fx.js +106 -0
- package/packages/helpers/src/humanize.js +14 -0
- package/packages/helpers/src/map.js +3 -0
- package/packages/styles/README.md +37 -0
- package/packages/styles/package.json +15 -0
- package/packages/styles/src/_action-bar.scss +35 -0
- package/packages/styles/src/_admin.scss +22 -0
- package/packages/styles/src/_animate.scss +1579 -0
- package/packages/styles/src/_badges.scss +34 -0
- package/packages/styles/src/_category-list.scss +14 -0
- package/packages/styles/src/_common.scss +163 -0
- package/packages/styles/src/_info-box.scss +96 -0
- package/packages/styles/src/_left-nav.scss +59 -0
- package/packages/styles/src/_loader.scss +82 -0
- package/packages/styles/src/_menu-sorter.scss +39 -0
- package/packages/styles/src/_model-creator.scss +48 -0
- package/packages/styles/src/_module-permission.scss +25 -0
- package/packages/styles/src/_page-manager.scss +63 -0
- package/packages/styles/src/_popover-modal.scss +20 -0
- package/packages/styles/src/_table-grid.scss +39 -0
- package/packages/styles/src/_toast.scss +20 -0
- package/packages/styles/src/_variables.scss +37 -0
- package/packages/styles/src/app.scss +2 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="btn-toolbar justify-content-between border-bottom mb-2 pb-2"
|
|
4
|
+
role="toolbar"
|
|
5
|
+
>
|
|
6
|
+
<div class="btn-group" role="group">
|
|
7
|
+
<small style="position: relative; top: 5px" v-if="showExpand">
|
|
8
|
+
<left-menu-toggle
|
|
9
|
+
data-icon-css="fa fa-arrow-left hand"
|
|
10
|
+
data-icon-css-off="fa fa-arrow-right hand"
|
|
11
|
+
></left-menu-toggle
|
|
12
|
+
></small>
|
|
13
|
+
<h4 class="moduleTitle" v-html="title"></h4>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="input-group actionToolbar">
|
|
16
|
+
<copy-paste
|
|
17
|
+
:data-copy-paste-auto-init="dataCopyPasteAutoInit"
|
|
18
|
+
:data-show-copy="dataShowCopy"
|
|
19
|
+
:data-show-paste="dataShowPaste"
|
|
20
|
+
></copy-paste>
|
|
21
|
+
<button
|
|
22
|
+
v-if="showBackButton"
|
|
23
|
+
aria-label="Back"
|
|
24
|
+
class="btn btn-outline-secondary"
|
|
25
|
+
title="Back"
|
|
26
|
+
type="button"
|
|
27
|
+
@click="goBack()"
|
|
28
|
+
>
|
|
29
|
+
{{ backTitle }}
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script>
|
|
36
|
+
import CopyPaste from "./library/copy-paste.vue";
|
|
37
|
+
import LeftMenuShowHide from "./library/left-menu-show-hide.vue";
|
|
38
|
+
|
|
39
|
+
export default {
|
|
40
|
+
components: {
|
|
41
|
+
"copy-paste": CopyPaste,
|
|
42
|
+
"left-menu-toggle": LeftMenuShowHide,
|
|
43
|
+
},
|
|
44
|
+
mounted() {},
|
|
45
|
+
props: [
|
|
46
|
+
"dataTitle",
|
|
47
|
+
"dataBackUrl",
|
|
48
|
+
"dataBackTitle",
|
|
49
|
+
"dataShowCopy",
|
|
50
|
+
"dataShowPaste",
|
|
51
|
+
"dataCopyPasteAutoInit",
|
|
52
|
+
"dataShowExpand",
|
|
53
|
+
],
|
|
54
|
+
computed: {
|
|
55
|
+
showBackButton() {
|
|
56
|
+
return typeof this.dataBackUrl !== "undefined";
|
|
57
|
+
},
|
|
58
|
+
showExpand() {
|
|
59
|
+
return typeof this.dataShowExpand !== "undefined";
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
data() {
|
|
63
|
+
return {
|
|
64
|
+
title: this.dataTitle,
|
|
65
|
+
backUrl: this.dataBackUrl,
|
|
66
|
+
backTitle:
|
|
67
|
+
typeof this.dataBackTitle === "undefined" ? "Back" : this.dataBackTitle,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
methods: {
|
|
71
|
+
goBack() {
|
|
72
|
+
window.location.href = this.backUrl;
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
</script>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<nav class="navbar navbar-expand-lg bg-light border-bottom">
|
|
3
|
+
<div class="container-fluid">
|
|
4
|
+
<a class="navbar-brand" href="/" target="_blank"
|
|
5
|
+
><img class="cms-logo" :src="logo" :height="logoHeight" />
|
|
6
|
+
{{ siteName }}
|
|
7
|
+
</a>
|
|
8
|
+
<button
|
|
9
|
+
class="navbar-toggler"
|
|
10
|
+
type="button"
|
|
11
|
+
data-bs-toggle="collapse"
|
|
12
|
+
data-bs-target="#navbarScroll"
|
|
13
|
+
aria-controls="navbarScroll"
|
|
14
|
+
aria-expanded="false"
|
|
15
|
+
aria-label="Toggle navigation"
|
|
16
|
+
>
|
|
17
|
+
<span class="navbar-toggler-icon"></span>
|
|
18
|
+
</button>
|
|
19
|
+
<div class="collapse navbar-collapse" id="navbarScroll">
|
|
20
|
+
<ul
|
|
21
|
+
class="navbar-nav me-auto my-2 my-lg-0 navbar-nav-scroll"
|
|
22
|
+
style="--bs-scroll-height: 100px"
|
|
23
|
+
>
|
|
24
|
+
<li class="nav-item">
|
|
25
|
+
<global-site-button
|
|
26
|
+
:data-current-site="dataCurrentSite"
|
|
27
|
+
:data-supported-sites="dataSupportedSites"
|
|
28
|
+
:data-is-admin="dataIsAdmin"
|
|
29
|
+
></global-site-button>
|
|
30
|
+
</li>
|
|
31
|
+
</ul>
|
|
32
|
+
<div class="d-flex">
|
|
33
|
+
Welcome <span class="text-success">{{ userName }}!</span>
|
|
34
|
+
<ul
|
|
35
|
+
class="navbar-nav me-auto my-2 my-lg-0 navbar-nav-scroll ms-1"
|
|
36
|
+
style="--bs-scroll-height: 100px"
|
|
37
|
+
>
|
|
38
|
+
<li class="nav-item">
|
|
39
|
+
<a href="/logout" @click.prevent="logout">Logout</a>
|
|
40
|
+
</li>
|
|
41
|
+
</ul>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</nav>
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<script>
|
|
49
|
+
import AdminConfig from "@hashtagcms/helpers/admin-config";
|
|
50
|
+
import GlobalSiteButton from "./global-site-button.vue";
|
|
51
|
+
export default {
|
|
52
|
+
components: {
|
|
53
|
+
"global-site-button": GlobalSiteButton,
|
|
54
|
+
},
|
|
55
|
+
mounted() {
|
|
56
|
+
//console.log('dataCurrentSite '+this.dataCurrentSite);
|
|
57
|
+
},
|
|
58
|
+
props: [
|
|
59
|
+
"dataUsername",
|
|
60
|
+
"dataSiteName",
|
|
61
|
+
"dataCurrentSite",
|
|
62
|
+
"dataSupportedSites",
|
|
63
|
+
"dataIsAdmin",
|
|
64
|
+
"dataSiteCombo",
|
|
65
|
+
"dataLogo",
|
|
66
|
+
"dataLogoHeight",
|
|
67
|
+
],
|
|
68
|
+
computed: {
|
|
69
|
+
logo() {
|
|
70
|
+
return typeof this.dataLogo !== "undefined" && this.dataLogo !== ""
|
|
71
|
+
? this.dataLogo
|
|
72
|
+
: AdminConfig.admin_asset("img/logo-transparent.png");
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
data() {
|
|
76
|
+
return {
|
|
77
|
+
siteName: this.dataSiteName || "hashtagcms.org",
|
|
78
|
+
userName: this.dataUsername,
|
|
79
|
+
isLoggedIn: !!(this.dataUsername && this.dataUsername !== ""),
|
|
80
|
+
siteCombo: !(
|
|
81
|
+
typeof this.dataSiteCombo == "undefined" ||
|
|
82
|
+
this.dataSiteCombo === "false"
|
|
83
|
+
),
|
|
84
|
+
logoHeight:
|
|
85
|
+
typeof this.dataLogoHeight === "undefined" || this.dataLogoHeight === ""
|
|
86
|
+
? 50
|
|
87
|
+
: this.dataLogoHeight,
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
methods: {
|
|
91
|
+
logout(event) {
|
|
92
|
+
document.getElementById("logout-form").submit();
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
</script>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @hashtagcms/helpers
|
|
2
|
+
|
|
3
|
+
A utility toolbelt for HashtagCMS development. This package provides essential classes for API communication, form handling, configuration management, and event management.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @hashtagcms/helpers
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 🚀 Usage
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { Toast, Loader } from "@hashtagcms/helpers/common";
|
|
15
|
+
import Form from "@hashtagcms/helpers/form";
|
|
16
|
+
import AdminConfig from "@hashtagcms/helpers/admin-config";
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 🛠 API Reference
|
|
20
|
+
|
|
21
|
+
### `Form`
|
|
22
|
+
|
|
23
|
+
A robust class for handling form state, validation, and submission via Axios.
|
|
24
|
+
|
|
25
|
+
**Usage:**
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
let myForm = new Form({ name: "", email: "" });
|
|
29
|
+
|
|
30
|
+
// Submit
|
|
31
|
+
myForm
|
|
32
|
+
.post("/api/user/create")
|
|
33
|
+
.then((data) => console.log("Saved!"))
|
|
34
|
+
.catch((errors) => console.log(myForm.errors.get("email")));
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Features:**
|
|
38
|
+
|
|
39
|
+
- **`post(url)`, `put(url)`, `delete(url)`**: wrappers for API calls.
|
|
40
|
+
- **`reset()`**: Clears fields and errors.
|
|
41
|
+
- **`errors.get('field')`**: Retrieve validation error for a field.
|
|
42
|
+
- **`data()`**: Returns the clean data object for submission.
|
|
43
|
+
|
|
44
|
+
### `AdminConfig` (Default Export)
|
|
45
|
+
|
|
46
|
+
A singleton that manages application-wide settings passed from the server (usually via `window.Laravel`).
|
|
47
|
+
|
|
48
|
+
**Methods:**
|
|
49
|
+
|
|
50
|
+
- **`admin_path(path)`**: Generates a full URL for the admin panel.
|
|
51
|
+
- **`admin_asset(path)`**: Generates a URL for theme assets.
|
|
52
|
+
- **`get_media(path)`**: Generates a URL for media files.
|
|
53
|
+
|
|
54
|
+
### `EventBus`
|
|
55
|
+
|
|
56
|
+
A lightweight wrapper around `mitt` to handle cross-component communication.
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
import { EventBus } from "@hashtagcms/helpers/event-bus";
|
|
60
|
+
|
|
61
|
+
// Send
|
|
62
|
+
EventBus.emit("my-event", { id: 1 });
|
|
63
|
+
|
|
64
|
+
// Listen
|
|
65
|
+
EventBus.on("my-event", (data) => {
|
|
66
|
+
console.log(data.id);
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `Common` Utilities
|
|
71
|
+
|
|
72
|
+
Exported from `@hashtagcms/helpers/common`:
|
|
73
|
+
|
|
74
|
+
- **`Toast`**: Displays global toast notifications.
|
|
75
|
+
- `Toast.show(vm, message, timeout, position)`
|
|
76
|
+
- **`Loader`**: Controls the global loading spinner.
|
|
77
|
+
- `Loader.show(vm, msg)`, `Loader.hide(vm)`
|
|
78
|
+
- **`Modal`**: Controls the global modal dialog.
|
|
79
|
+
- **`queryBuilder`**: Helper to parse URL query parameters.
|
|
80
|
+
- **`CopyToClipboard(text)`**: Async helper to copy text to clipboard.
|
|
81
|
+
- **`PasteFromClipboard()`**: Async helper to read from clipboard.
|
|
82
|
+
|
|
83
|
+
## ⚠️ Dependencies
|
|
84
|
+
|
|
85
|
+
This package depends on:
|
|
86
|
+
|
|
87
|
+
- `axios`: For HTTP requests.
|
|
88
|
+
- `mitt`: For event handling.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hashtagcms/helpers",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Helper utilities for HashtagCMS",
|
|
5
|
+
"author": "HashtagCMS",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://hashtagcms.org",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/hashtagcms/admin-ui-kit.git"
|
|
11
|
+
},
|
|
12
|
+
"main": "src/common.js",
|
|
13
|
+
"exports": {
|
|
14
|
+
"./*": "./src/*.js"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"mitt": "^3.0.1",
|
|
18
|
+
"axios": "^1.8.4"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Created by marghoob.suleman on 8/23/17.
|
|
3
|
+
*/
|
|
4
|
+
import { EventBus } from "./event-bus";
|
|
5
|
+
import {
|
|
6
|
+
queryBuilder,
|
|
7
|
+
Storage,
|
|
8
|
+
Utils,
|
|
9
|
+
Fetcher,
|
|
10
|
+
CopyToClipboard,
|
|
11
|
+
PasteFromClipboard,
|
|
12
|
+
IsJson,
|
|
13
|
+
LeftMenu,
|
|
14
|
+
TitleCase
|
|
15
|
+
} from "@hashtagcms/admin-sdk";
|
|
16
|
+
|
|
17
|
+
// Initialize SDK LeftMenu with EventBus
|
|
18
|
+
if (LeftMenu && typeof LeftMenu.init === 'function') {
|
|
19
|
+
LeftMenu.init(EventBus);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
queryBuilder,
|
|
24
|
+
Storage,
|
|
25
|
+
Utils,
|
|
26
|
+
Fetcher,
|
|
27
|
+
CopyToClipboard,
|
|
28
|
+
PasteFromClipboard,
|
|
29
|
+
IsJson,
|
|
30
|
+
LeftMenu,
|
|
31
|
+
TitleCase
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Toast
|
|
36
|
+
* Dependecy: library/toastBox.vue
|
|
37
|
+
*
|
|
38
|
+
*/
|
|
39
|
+
export class Toast {
|
|
40
|
+
static show(vm, message = "", timeout = 1000, position) {
|
|
41
|
+
vm.$root.$refs.globalToaster.show(message, timeout, position);
|
|
42
|
+
}
|
|
43
|
+
static hide(vm) {
|
|
44
|
+
vm.$root.$refs.globalToaster.hide();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Loader
|
|
50
|
+
* Dependecy: library/loader.vue
|
|
51
|
+
*
|
|
52
|
+
*/
|
|
53
|
+
export class Loader {
|
|
54
|
+
static show(vm, message = null, position = null) {
|
|
55
|
+
vm.$root.$refs.globalLoader.show(message, position);
|
|
56
|
+
}
|
|
57
|
+
static hide(vm) {
|
|
58
|
+
vm.$root.$refs.globalLoader.hide();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Modal
|
|
64
|
+
* Dependency: library/modalBox.vue
|
|
65
|
+
*
|
|
66
|
+
*/
|
|
67
|
+
export class Modal {
|
|
68
|
+
static show(vm, message = "", position, callback, timeout) {
|
|
69
|
+
vm.$root.$refs.globalModalBox.show(message, position, callback, timeout);
|
|
70
|
+
}
|
|
71
|
+
static hide(vm) {
|
|
72
|
+
vm.$root.$refs.globalModalBox.hide();
|
|
73
|
+
}
|
|
74
|
+
static open(vm = null, modalRef = null, callback = null) {
|
|
75
|
+
if (vm != null && modalRef != null) {
|
|
76
|
+
vm.$refs[modalRef].open(callback);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
static close(vm = null, modalRef = null) {
|
|
80
|
+
if (vm != null && modalRef != null) {
|
|
81
|
+
vm.$refs[modalRef].hide();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Dashboard } from "@hashtagcms/admin-sdk";
|
|
2
|
+
|
|
3
|
+
export const {
|
|
4
|
+
data,
|
|
5
|
+
labelsCategories,
|
|
6
|
+
datasCategories,
|
|
7
|
+
labelsContent,
|
|
8
|
+
datasContent,
|
|
9
|
+
bgColors,
|
|
10
|
+
borderColors,
|
|
11
|
+
createChart,
|
|
12
|
+
makeData,
|
|
13
|
+
init
|
|
14
|
+
} = Dashboard;
|
|
15
|
+
|
|
16
|
+
export { Dashboard };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { AdminConfig, CleanForUrl } from "@hashtagcms/admin-sdk";
|
|
2
|
+
|
|
3
|
+
// Global AdminConfig instance wrapper if needed, or valid assuming window.AdminConfig is set.
|
|
4
|
+
// But better to use the class to be safe if window.AdminConfig isn't ready.
|
|
5
|
+
const adminConfig = new AdminConfig();
|
|
6
|
+
|
|
7
|
+
export const EditorHelper = (function () {
|
|
8
|
+
let makeRichEditor = (selector, settings) => {
|
|
9
|
+
selector = document.querySelector(selector);
|
|
10
|
+
let defaultSettings = {
|
|
11
|
+
selector: "#" + selector.id,
|
|
12
|
+
height: 500,
|
|
13
|
+
theme: "silver",
|
|
14
|
+
plugins:
|
|
15
|
+
"code print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern",
|
|
16
|
+
toolbar1:
|
|
17
|
+
"formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist | removeformat | customGallery | image | code ",
|
|
18
|
+
image_advtab: true,
|
|
19
|
+
template_popup_height: 400,
|
|
20
|
+
template_popup_width: 320,
|
|
21
|
+
valid_elements: "*[*]",
|
|
22
|
+
valid_children: "*[*]",
|
|
23
|
+
document_base_url: adminConfig.get("app_url") + "/",
|
|
24
|
+
allow_script_urls: true,
|
|
25
|
+
convert_urls: false,
|
|
26
|
+
relative_urls: false,
|
|
27
|
+
remove_script_host: false,
|
|
28
|
+
content_css: ["//fonts.googleapis.com/css?family=Lato:300,300i,400,400i"],
|
|
29
|
+
setup: function (editor) {
|
|
30
|
+
editor.ui.registry.addButton("customGallery", {
|
|
31
|
+
text: "Insert Image",
|
|
32
|
+
onAction: function (_) {
|
|
33
|
+
if (Vue?.$refs?.imageGallery) {
|
|
34
|
+
Vue.$refs.imageGallery.open(editor);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
defaultSettings = { ...defaultSettings, ...settings };
|
|
41
|
+
selector.editor = tinymce.init(defaultSettings);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return { makeRichEditor: makeRichEditor };
|
|
45
|
+
})();
|
|
46
|
+
|
|
47
|
+
/** Page Manager **/
|
|
48
|
+
export const PageManager = {
|
|
49
|
+
action: null,
|
|
50
|
+
content_type: null,
|
|
51
|
+
id: null,
|
|
52
|
+
init: function (action, content_type, id) {
|
|
53
|
+
this.action = action;
|
|
54
|
+
this.content_type = content_type;
|
|
55
|
+
this.id = id;
|
|
56
|
+
|
|
57
|
+
if (PageManager.action === "add") {
|
|
58
|
+
document
|
|
59
|
+
.getElementById("lang_name")
|
|
60
|
+
.addEventListener("change", PageManager.autoUpdateFields);
|
|
61
|
+
document
|
|
62
|
+
.getElementById("lang_title")
|
|
63
|
+
.addEventListener("change", PageManager.autoUpdateUrls);
|
|
64
|
+
document
|
|
65
|
+
.getElementById("link_rewrite")
|
|
66
|
+
.addEventListener("keyup", PageManager.linkRewriteUpdated);
|
|
67
|
+
document
|
|
68
|
+
.getElementById("category_id")
|
|
69
|
+
.addEventListener("change", PageManager.getParentCategory);
|
|
70
|
+
} else {
|
|
71
|
+
this.getParentCategory();
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
isBlank: function (elem) {
|
|
75
|
+
return document.getElementById(elem).value.replace(/\s/g, "") === "";
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
autoUpdateFields: function () {
|
|
79
|
+
let value = this.value;
|
|
80
|
+
try {
|
|
81
|
+
if (PageManager.isBlank("lang_title")) {
|
|
82
|
+
document.getElementById("lang_title").value =
|
|
83
|
+
value[0].toUpperCase() + value.slice(1);
|
|
84
|
+
document.getElementById("alias").value = CleanForUrl(
|
|
85
|
+
value.toUpperCase(),
|
|
86
|
+
"_",
|
|
87
|
+
);
|
|
88
|
+
let active_key = CleanForUrl(value.toLowerCase(), "-");
|
|
89
|
+
document.getElementById("lang_active_key").value = active_key;
|
|
90
|
+
document.getElementById("link_rewrite").value = active_key;
|
|
91
|
+
}
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.error(e.message);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
autoUpdateUrls: function () {
|
|
97
|
+
let value = this.value;
|
|
98
|
+
if (document.getElementById("link_rewrite").edited !== true) {
|
|
99
|
+
value = CleanForUrl(value.toUpperCase(), "_");
|
|
100
|
+
value = value.substr(0, 60); //it's limit
|
|
101
|
+
document.getElementById("alias").value = value;
|
|
102
|
+
|
|
103
|
+
let active_key = CleanForUrl(value.toLowerCase(), "-");
|
|
104
|
+
active_key = value.substr(0, 128); //it's limit
|
|
105
|
+
document.getElementById("lang_active_key").value = active_key;
|
|
106
|
+
document.getElementById("link_rewrite").value = active_key;
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
linkRewriteUpdated: function () {
|
|
110
|
+
document.getElementById("link_rewrite").edited = true;
|
|
111
|
+
},
|
|
112
|
+
getParentCategory() {
|
|
113
|
+
let parentcombo = document.getElementById("parent_id");
|
|
114
|
+
let category_id = document.getElementById("category_id").value;
|
|
115
|
+
document.getElementById("parent_id").value = "";
|
|
116
|
+
|
|
117
|
+
parentcombo.length = 0;
|
|
118
|
+
parentcombo.options[0] = new Option("Select", "");
|
|
119
|
+
|
|
120
|
+
if (category_id > 0) {
|
|
121
|
+
showHideBlock(true);
|
|
122
|
+
let path = adminConfig.admin_path("page/getParentCategory", {
|
|
123
|
+
content_type: PageManager.content_type,
|
|
124
|
+
category_id: category_id,
|
|
125
|
+
});
|
|
126
|
+
axios
|
|
127
|
+
.get(path)
|
|
128
|
+
.then(function (res) {
|
|
129
|
+
//console.log(res);
|
|
130
|
+
updateCombo(res.data);
|
|
131
|
+
})
|
|
132
|
+
.catch(function (res) {
|
|
133
|
+
//console.log(res);
|
|
134
|
+
showHideBlock(false);
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
showHideBlock(false);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function updateCombo(res) {
|
|
141
|
+
if (res.length > 0) {
|
|
142
|
+
let index = 1;
|
|
143
|
+
for (let i = 0; i < res.length; i++) {
|
|
144
|
+
let current = res[i];
|
|
145
|
+
if (current.id !== PageManager.id) {
|
|
146
|
+
parentcombo.options[index] = new Option(
|
|
147
|
+
current.lang.name,
|
|
148
|
+
current.id,
|
|
149
|
+
);
|
|
150
|
+
index++;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
showHideBlock(false);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function showHideBlock(show) {
|
|
159
|
+
document.getElementById("parent_div").style.display =
|
|
160
|
+
show === true ? "" : "none";
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Toast } from "./common";
|
|
2
|
+
|
|
3
|
+
export class ErrorMessage {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.errors = typeof error_messages == "undefined" ? [] : error_messages;
|
|
6
|
+
this.init();
|
|
7
|
+
}
|
|
8
|
+
init() {
|
|
9
|
+
let $this = this;
|
|
10
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
11
|
+
for (let i in $this.errors) {
|
|
12
|
+
$this.highlightField(i, $this.errors[i][0]);
|
|
13
|
+
}
|
|
14
|
+
$this.focusFirst();
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
highlightField(field, message) {
|
|
18
|
+
let f = field;
|
|
19
|
+
field = document.getElementById(f);
|
|
20
|
+
|
|
21
|
+
if (!field) {
|
|
22
|
+
console.error("Could not find " + f);
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
field.classList.add("is-invalid");
|
|
26
|
+
|
|
27
|
+
let div = document.createElement("div");
|
|
28
|
+
div.classList.add("alert", "alert-danger", "mt-03");
|
|
29
|
+
|
|
30
|
+
if (f.indexOf("lang_") !== -1) {
|
|
31
|
+
message = message.replace("lang ", "");
|
|
32
|
+
}
|
|
33
|
+
div.innerHTML = message;
|
|
34
|
+
|
|
35
|
+
field.parentNode.insertBefore(div, field.nextSibling);
|
|
36
|
+
}
|
|
37
|
+
focusFirst() {
|
|
38
|
+
for (let i in this.errors) {
|
|
39
|
+
let element = document.getElementById(i);
|
|
40
|
+
try {
|
|
41
|
+
if (element) {
|
|
42
|
+
element.focus();
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.log(e.message);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|