mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-11-15 23:00:10 +00:00
add preview to Announcements
This commit is contained in:
parent
2c6d08319b
commit
c0f316d049
5
api.go
5
api.go
@ -1712,6 +1712,9 @@ func (app *appContext) GetCustomEmailTemplate(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
writeVars = func(variables []string) { app.storage.customEmails.UserExpired.Variables = variables }
|
writeVars = func(variables []string) { app.storage.customEmails.UserExpired.Variables = variables }
|
||||||
values = app.email.userExpiredValues(app, false)
|
values = app.email.userExpiredValues(app, false)
|
||||||
|
// Just send the email html
|
||||||
|
case "Announcement":
|
||||||
|
content = ""
|
||||||
default:
|
default:
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
@ -1747,7 +1750,7 @@ func (app *appContext) GetCustomEmailTemplate(gc *gin.Context) {
|
|||||||
respondBool(500, false, gc)
|
respondBool(500, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
email, err := app.email.constructTemplate("", "<div id=\"preview-content\"></div>", app)
|
email, err := app.email.constructTemplate("", "<div class=\"preview-content\"></div>", app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondBool(500, false, gc)
|
respondBool(500, false, gc)
|
||||||
return
|
return
|
||||||
|
@ -156,9 +156,10 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id="modal-announce" class="modal">
|
<div id="modal-announce" class="modal">
|
||||||
<form class="modal-content card" id="form-announce" href="">
|
<form class="modal-content wide card" id="form-announce" href="">
|
||||||
<span class="heading"><span id="header-announce"></span> <span class="modal-close">×</span></span>
|
<span class="heading"><span id="header-announce"></span> <span class="modal-close">×</span></span>
|
||||||
<div class="content mt-half">
|
<div class="row">
|
||||||
|
<div class="col flex-col content mt-half">
|
||||||
<label class="label supra" for="announce-subject"> {{ .strings.subject }}</label>
|
<label class="label supra" for="announce-subject"> {{ .strings.subject }}</label>
|
||||||
<input type="text" id="announce-subject" class="input ~neutral !normal mb-1 mt-half">
|
<input type="text" id="announce-subject" class="input ~neutral !normal mb-1 mt-half">
|
||||||
<label class="label supra" for="textarea-announce">{{ .strings.message }}</label>
|
<label class="label supra" for="textarea-announce">{{ .strings.message }}</label>
|
||||||
@ -169,6 +170,11 @@
|
|||||||
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
<span class="button ~urge !normal full-width center supra submit">{{ .strings.submit }}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col card ~neutral !low">
|
||||||
|
<span class="subheading supra">{{ .strings.preview }}</span>
|
||||||
|
<div class="mt-half" id="announce-preview"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id="modal-customize" class="modal">
|
<div id="modal-customize" class="modal">
|
||||||
|
13
package-lock.json
generated
13
package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ts-stack/markdown": "^1.3.0",
|
"@ts-stack/markdown": "^1.3.0",
|
||||||
|
"@types/node": "^15.0.1",
|
||||||
"a17t": "^0.4.0",
|
"a17t": "^0.4.0",
|
||||||
"esbuild": "^0.8.57",
|
"esbuild": "^0.8.57",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
@ -35,9 +36,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "14.14.16",
|
"version": "15.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-14.14.16.tgz?cache=0&sync_timestamp=1608756036972&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.14.16.tgz",
|
"resolved": "https://registry.nlark.com/@types/node/download/@types/node-15.0.1.tgz?cache=0&sync_timestamp=1619534647758&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-15.0.1.tgz",
|
||||||
"integrity": "sha1-PMNR+NSBAd6t/tTJ5PEWBI1De0s="
|
"integrity": "sha1-7zTeoIgQKNETmL5b9OhWdD49w1o="
|
||||||
},
|
},
|
||||||
"node_modules/a17t": {
|
"node_modules/a17t": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
@ -1835,9 +1836,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.14.16",
|
"version": "15.0.1",
|
||||||
"resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-14.14.16.tgz?cache=0&sync_timestamp=1608756036972&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.14.16.tgz",
|
"resolved": "https://registry.nlark.com/@types/node/download/@types/node-15.0.1.tgz?cache=0&sync_timestamp=1619534647758&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-15.0.1.tgz",
|
||||||
"integrity": "sha1-PMNR+NSBAd6t/tTJ5PEWBI1De0s="
|
"integrity": "sha1-7zTeoIgQKNETmL5b9OhWdD49w1o="
|
||||||
},
|
},
|
||||||
"a17t": {
|
"a17t": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"homepage": "https://github.com/hrfee/jfa-go#readme",
|
"homepage": "https://github.com/hrfee/jfa-go#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ts-stack/markdown": "^1.3.0",
|
"@ts-stack/markdown": "^1.3.0",
|
||||||
|
"@types/node": "^15.0.1",
|
||||||
"a17t": "^0.4.0",
|
"a17t": "^0.4.0",
|
||||||
"esbuild": "^0.8.57",
|
"esbuild": "^0.8.57",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import { _get, _post, _delete, toggleLoader, toDateString } from "../modules/common.js";
|
import { _get, _post, _delete, toggleLoader, toDateString } from "../modules/common.js";
|
||||||
|
import { templateEmail } from "../modules/settings.js";
|
||||||
|
import { Marked } from "@ts-stack/markdown";
|
||||||
|
import { stripMarkdown } from "../modules/stripmd.js";
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
@ -193,6 +196,9 @@ export class accountsList {
|
|||||||
|
|
||||||
private _addUserButton = document.getElementById("accounts-add-user") as HTMLSpanElement;
|
private _addUserButton = document.getElementById("accounts-add-user") as HTMLSpanElement;
|
||||||
private _announceButton = document.getElementById("accounts-announce") as HTMLSpanElement;
|
private _announceButton = document.getElementById("accounts-announce") as HTMLSpanElement;
|
||||||
|
private _announcePreview: HTMLElement;
|
||||||
|
private _previewLoaded = false;
|
||||||
|
private _announceTextarea = document.getElementById("textarea-announce") as HTMLTextAreaElement;
|
||||||
private _deleteUser = document.getElementById("accounts-delete-user") as HTMLSpanElement;
|
private _deleteUser = document.getElementById("accounts-delete-user") as HTMLSpanElement;
|
||||||
private _disableEnable = document.getElementById("accounts-disable-enable") as HTMLSpanElement;
|
private _disableEnable = document.getElementById("accounts-disable-enable") as HTMLSpanElement;
|
||||||
private _deleteNotify = document.getElementById("delete-user-notify") as HTMLInputElement;
|
private _deleteNotify = document.getElementById("delete-user-notify") as HTMLInputElement;
|
||||||
@ -432,7 +438,16 @@ export class accountsList {
|
|||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
loadPreview = () => {
|
||||||
|
let content = this._announceTextarea.value;
|
||||||
|
if (!this._previewLoaded) {
|
||||||
|
content = stripMarkdown(content);
|
||||||
|
this._announcePreview.textContent = content;
|
||||||
|
} else {
|
||||||
|
content = Marked.parse(content);
|
||||||
|
this._announcePreview.innerHTML = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
announce = () => {
|
announce = () => {
|
||||||
const modalHeader = document.getElementById("header-announce");
|
const modalHeader = document.getElementById("header-announce");
|
||||||
modalHeader.textContent = window.lang.quantity("announceTo", this._collectUsers().length);
|
modalHeader.textContent = window.lang.quantity("announceTo", this._collectUsers().length);
|
||||||
@ -440,16 +455,16 @@ export class accountsList {
|
|||||||
let list = this._collectUsers();
|
let list = this._collectUsers();
|
||||||
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
||||||
const subject = document.getElementById("announce-subject") as HTMLInputElement;
|
const subject = document.getElementById("announce-subject") as HTMLInputElement;
|
||||||
const message = document.getElementById("textarea-announce") as HTMLTextAreaElement;
|
|
||||||
subject.value = "";
|
subject.value = "";
|
||||||
message.value = "";
|
this._announceTextarea.value = "";
|
||||||
form.onsubmit = (event: Event) => {
|
form.onsubmit = (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
toggleLoader(button);
|
toggleLoader(button);
|
||||||
let send = {
|
let send = {
|
||||||
"users": list,
|
"users": list,
|
||||||
"subject": subject.value,
|
"subject": subject.value,
|
||||||
"message": message.value
|
"message": this._announceTextarea.value
|
||||||
}
|
}
|
||||||
_post("/users/announce", send, (req: XMLHttpRequest) => {
|
_post("/users/announce", send, (req: XMLHttpRequest) => {
|
||||||
if (req.readyState == 4) {
|
if (req.readyState == 4) {
|
||||||
@ -463,7 +478,29 @@ export class accountsList {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
_get("/config/emails/Announcement", null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
const preview = document.getElementById("announce-preview") as HTMLDivElement;
|
||||||
|
if (req.status != 200) {
|
||||||
|
preview.innerHTML = `<pre class="preview-content" class="monospace"></pre>`;
|
||||||
window.modals.announce.show();
|
window.modals.announce.show();
|
||||||
|
this._previewLoaded = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let templ = req.response as templateEmail;
|
||||||
|
if (!templ.html) {
|
||||||
|
preview.innerHTML = `<pre class="preview-content" class="monospace"></pre>`;
|
||||||
|
this._previewLoaded = false;
|
||||||
|
} else {
|
||||||
|
preview.innerHTML = templ.html;
|
||||||
|
this._previewLoaded = true;
|
||||||
|
}
|
||||||
|
this._announcePreview = preview.getElementsByClassName("preview-content")[0] as HTMLElement;
|
||||||
|
this.loadPreview();
|
||||||
|
window.modals.announce.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
enableDisableUsers = () => {
|
enableDisableUsers = () => {
|
||||||
@ -750,6 +787,8 @@ export class accountsList {
|
|||||||
}
|
}
|
||||||
this._checkCheckCount();
|
this._checkCheckCount();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this._announceTextarea.onkeyup = this.loadPreview;
|
||||||
}
|
}
|
||||||
|
|
||||||
reload = () => _get("/users", null, (req: XMLHttpRequest) => {
|
reload = () => _get("/users", null, (req: XMLHttpRequest) => {
|
||||||
|
@ -157,7 +157,7 @@ class DOMInvite implements Invite {
|
|||||||
this._createdUnix = unix;
|
this._createdUnix = unix;
|
||||||
const el = this._middle.querySelector("strong.inv-created");
|
const el = this._middle.querySelector("strong.inv-created");
|
||||||
if (unix == 0) {
|
if (unix == 0) {
|
||||||
el.textContent = "n/a";
|
el.textContent = window.lang.strings("unknown");
|
||||||
} else {
|
} else {
|
||||||
el.textContent = toDateString(new Date(unix*1000));
|
el.textContent = toDateString(new Date(unix*1000));
|
||||||
}
|
}
|
||||||
@ -479,7 +479,7 @@ export class inviteList implements inviteList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function parseInvite(invite: { [f: string]: string | number | string[][] | boolean }): Invite {
|
function parseInvite(invite: { [f: string]: string | number | { [name: string]: number } | boolean }): Invite {
|
||||||
let parsed: Invite = {};
|
let parsed: Invite = {};
|
||||||
parsed.code = invite["code"] as string;
|
parsed.code = invite["code"] as string;
|
||||||
parsed.email = invite["email"] as string || "";
|
parsed.email = invite["email"] as string || "";
|
||||||
@ -509,8 +509,8 @@ function parseInvite(invite: { [f: string]: string | number | string[][] | boole
|
|||||||
parsed.userExpiry = invite["user-expiry"] as boolean;
|
parsed.userExpiry = invite["user-expiry"] as boolean;
|
||||||
parsed.userExpiryTime = userExpiryTime.slice(0, -1);
|
parsed.userExpiryTime = userExpiryTime.slice(0, -1);
|
||||||
parsed.remainingUses = invite["no-limit"] ? "∞" : String(invite["remaining-uses"])
|
parsed.remainingUses = invite["no-limit"] ? "∞" : String(invite["remaining-uses"])
|
||||||
parsed.usedBy = invite["used-by"] as string[][] || [];
|
parsed.usedBy = invite["used-by"] as { [name: string]: number } || {} ;
|
||||||
parsed.created = invite["created"] as string || window.lang.strings("unknown");
|
parsed.created = invite["created"] as number || 0;
|
||||||
parsed.profile = invite["profile"] as string || "";
|
parsed.profile = invite["profile"] as string || "";
|
||||||
parsed.notifyExpiry = invite["notify-expiry"] as boolean || false;
|
parsed.notifyExpiry = invite["notify-expiry"] as boolean || false;
|
||||||
parsed.notifyCreation = invite["notify-creation"] as boolean || false;
|
parsed.notifyCreation = invite["notify-creation"] as boolean || false;
|
||||||
|
@ -766,7 +766,7 @@ class ombiDefaults {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface templateEmail {
|
export interface templateEmail {
|
||||||
content: string;
|
content: string;
|
||||||
variables: string[];
|
variables: string[];
|
||||||
conditionals: string[];
|
conditionals: string[];
|
||||||
@ -829,11 +829,11 @@ class EmailEditor {
|
|||||||
this._templ = req.response as templateEmail;
|
this._templ = req.response as templateEmail;
|
||||||
this._textArea.value = this._templ.content;
|
this._textArea.value = this._templ.content;
|
||||||
if (this._templ.html == "") {
|
if (this._templ.html == "") {
|
||||||
this._preview.innerHTML = `<pre id="preview-content" class="monospace"></pre>`;
|
this._preview.innerHTML = `<pre class="preview-content" class="monospace"></pre>`;
|
||||||
} else {
|
} else {
|
||||||
this._preview.innerHTML = this._templ.html;
|
this._preview.innerHTML = this._templ.html;
|
||||||
}
|
}
|
||||||
this._previewContent = document.getElementById("preview-content");
|
this._previewContent = this._preview.getElementsByClassName("preview-content")[0] as HTMLElement;
|
||||||
this.loadPreview();
|
this.loadPreview();
|
||||||
this._content = this._templ.content;
|
this._content = this._templ.content;
|
||||||
const colors = ["info", "urge", "positive", "neutral"];
|
const colors = ["info", "urge", "positive", "neutral"];
|
||||||
|
6
views.go
6
views.go
@ -53,13 +53,15 @@ func (app *appContext) pushResources(gc *gin.Context, admin bool) {
|
|||||||
gc.Header("Link", cssHeader)
|
gc.Header("Link", cssHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Page int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AdminPage = iota + 1
|
AdminPage Page = iota + 1
|
||||||
FormPage
|
FormPage
|
||||||
PWRPage
|
PWRPage
|
||||||
)
|
)
|
||||||
|
|
||||||
func (app *appContext) getLang(gc *gin.Context, page int, chosen string) string {
|
func (app *appContext) getLang(gc *gin.Context, page Page, chosen string) string {
|
||||||
lang := gc.Query("lang")
|
lang := gc.Query("lang")
|
||||||
cookie, err := gc.Cookie("lang")
|
cookie, err := gc.Cookie("lang")
|
||||||
if lang != "" {
|
if lang != "" {
|
||||||
|
Loading…
Reference in New Issue
Block a user