node-red-contrib-notification-better 1.1.0 → 1.2.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/README.md +11 -8
- package/locales/en-US/noti-better.html +0 -0
- package/locales/en-US/{ui_notification_better.json → noti-better.json} +11 -11
- package/locales/ja/{ui_notification_better.json → noti-better.json} +8 -8
- package/locales/zh-CN/noti-better.json +63 -0
- package/locales/zh-TW/noti-better.html +0 -0
- package/locales/zh-TW/{ui_notification_better.json → noti-better.json} +14 -14
- package/package.json +3 -2
- package/ui_notification.html +140 -70
- package/ui_notification.js +26 -26
- package/locales/en-US/ui_notification_better.html +0 -50
- package/locales/zh-CN/ui_notification_better.json +0 -58
- package/locales/zh-TW/ui_notification_better.html +0 -50
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# node-red-contrib-notification-better
|
|
2
2
|
|
|
3
|
-
一個為 [Node-RED Dashboard](https://flows.nodered.org/node/node-red-dashboard) 設計的進階通知(Notification / Toast)與互動對話框(Dialog / Prompt
|
|
3
|
+
一個為 [Node-RED Dashboard](https://flows.nodered.org/node/node-red-dashboard) 設計的進階通知(Notification / Toast)與互動對話框(Dialog / Prompt)節點:**`noti-better`**。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
徹底解決按鈕強制大寫的問題,支援完美暗黑主題相容介面、完整多語言、通知等級色彩、提示音效與倒數進度條!
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -11,15 +11,18 @@
|
|
|
11
11
|
- 🔤 **忠實保留按鈕原始大小寫 (Preserve Button Case)**:
|
|
12
12
|
- 徹底解除 Angular Material 強制全大寫(`text-transform: uppercase`)的限制。
|
|
13
13
|
- 輸入 `Ok` 顯示 `Ok`、輸入 `Cancel` 顯示 `Cancel`、輸入 `確定` 或 `Close Now` 皆忠實依字樣呈現!
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
14
|
+
- 🌓 **完美相容深色 / 淺色主題 (Dark & Light Theme Friendly)**:
|
|
15
|
+
- 表單標題與排版無縫融入 Node-RED 介面,在暗黑模式下無突兀白底,文字清晰舒適。
|
|
16
|
+
- 🛡️ **雙重多語言防呆機制 (Robust i18n & Fallback)**:
|
|
17
|
+
- 完整支援 **繁體中文 (zh-TW)**、**English (en-US)**、**日本語 (ja)**、**簡體中文 (zh-CN)**。
|
|
18
|
+
- 所有表單欄位與畫布標籤皆內嵌完整的預設降級文字,即使語系載入延遲也絕不出現空白或程式代碼字樣。
|
|
19
|
+
- 🎯 **五種通知等級預設 (Notification Levels)**:
|
|
17
20
|
- 內建 **Info (資訊)**、**Success (成功)**、**Warning (警告)**、**Error (錯誤)** 與 **Default (預設)**。
|
|
18
|
-
- 自動套用專屬主題色彩與外框線,亦可透過 `msg.notificationType`
|
|
21
|
+
- 自動套用專屬主題色彩與外框線,亦可透過 `msg.notificationType` 動態切換。
|
|
19
22
|
- 🔔 **圖示支援 (Icon Support)**:
|
|
20
23
|
- 自動根據通知等級配對 Font Awesome 圖示,亦可手動填寫或透過 `msg.icon` 自訂圖示。
|
|
21
24
|
- 🔊 **音效提示 (Audio Chime Alert)**:
|
|
22
|
-
- 內建 Web Audio API
|
|
25
|
+
- 內建 Web Audio API 音效合成技術,無須外掛任何音訊檔案,勾選或由 `msg.playSound: true` 觸發即可發出清脆提示聲。
|
|
23
26
|
- ⏳ **倒數進度條 (Countdown Progress Bar)**:
|
|
24
27
|
- 在卡片底部以視覺化動態進度條呈現剩餘時間,何時關閉一目了然。
|
|
25
28
|
- 💬 **互動式對話框與輸入框 (Dialog & Prompt)**:
|
|
@@ -53,7 +56,7 @@ npm install node-red-contrib-notification-better
|
|
|
53
56
|
|
|
54
57
|
## 🛠️ 使用與訊息屬性說明 (Message Properties)
|
|
55
58
|
|
|
56
|
-
安裝完成後,會在左側節點列表(Palette)的 **dashboard** 分類中顯示
|
|
59
|
+
安裝完成後,會在左側節點列表(Palette)的 **dashboard** 分類中顯示 **`noti-better`** 節點。
|
|
57
60
|
|
|
58
61
|
### 支援的輸入訊息屬性 (Inputs)
|
|
59
62
|
|
|
File without changes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"paletteLabel": "
|
|
2
|
+
"noti-better": {
|
|
3
|
+
"paletteLabel": "noti-better",
|
|
4
4
|
"label": {
|
|
5
5
|
"position": "Layout",
|
|
6
|
-
"notificationType": "Type
|
|
6
|
+
"notificationType": "Notification Type",
|
|
7
7
|
"displayTime": "Timeout (sec)",
|
|
8
8
|
"highlight": "Border Color",
|
|
9
9
|
"showIcon": "Show Icon",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"raw": "Accept raw HTML / JavaScript in msg.payload",
|
|
20
20
|
"className": "Custom CSS Class",
|
|
21
21
|
"topic": "Topic / Title",
|
|
22
|
-
"name": "Name",
|
|
22
|
+
"name": "Node Name",
|
|
23
23
|
"showDialog": "show dialog",
|
|
24
|
-
"showNotification": "
|
|
24
|
+
"showNotification": "noti-better"
|
|
25
25
|
},
|
|
26
26
|
"option": {
|
|
27
27
|
"topRight": "Top Right",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"timeout": "e.g. 3 or [msg.timeout]",
|
|
41
41
|
"highlight": "e.g. #ff0000 or red",
|
|
42
42
|
"customIcon": "e.g. fa-bell, fa-check",
|
|
43
|
-
"ok": "
|
|
44
|
-
"cancel": "
|
|
45
|
-
"promptDefault": "Optional default
|
|
46
|
-
"promptPlaceholder": "
|
|
43
|
+
"ok": "e.g. Ok, Confirm, 確定",
|
|
44
|
+
"cancel": "e.g. Cancel, 取消",
|
|
45
|
+
"promptDefault": "Optional default value",
|
|
46
|
+
"promptPlaceholder": "Placeholder in text box",
|
|
47
47
|
"className": "[msg.className]",
|
|
48
|
-
"topic": "[msg.topic]",
|
|
48
|
+
"topic": "[msg.topic] or custom title",
|
|
49
49
|
"name": "Node name"
|
|
50
50
|
},
|
|
51
51
|
"section": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"tip": {
|
|
58
58
|
"raw": "<b>Security Notice</b>: Allowing raw HTML/JavaScript can enable code execution. Only enable this if the message payload originates from a trusted source.",
|
|
59
|
-
"icon": "Enter Font Awesome 4 icon name (e.g. fa-bell
|
|
59
|
+
"icon": "Enter Font Awesome 4 icon name (e.g. fa-bell). If enabled without custom icon, an icon matching the notification type will automatically be displayed.",
|
|
60
60
|
"preserveCase": "When checked, button text will exactly match what you typed instead of being forced into uppercase by Angular Material."
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"paletteLabel": "
|
|
2
|
+
"noti-better": {
|
|
3
|
+
"paletteLabel": "noti-better",
|
|
4
4
|
"label": {
|
|
5
5
|
"position": "表示位置",
|
|
6
|
-
"notificationType": "通知タイプ
|
|
6
|
+
"notificationType": "通知タイプ",
|
|
7
7
|
"displayTime": "表示時間 (秒)",
|
|
8
8
|
"highlight": "枠線の色",
|
|
9
9
|
"showIcon": "アイコンを表示",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"showCountdown": "カウントダウンバーを表示",
|
|
13
13
|
"preserveCase": "ボタンの大文字強制を無効化 (入力通り表示)",
|
|
14
14
|
"sendall": "全ブラウザセッションに送信",
|
|
15
|
-
"ok": "
|
|
15
|
+
"ok": "確認ボタン",
|
|
16
16
|
"cancel": "キャンセルボタン",
|
|
17
17
|
"promptDefault": "入力欄の初期値",
|
|
18
18
|
"promptPlaceholder": "入力欄のプレースホルダー",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"topic": "トピック / タイトル",
|
|
22
22
|
"name": "ノード名",
|
|
23
23
|
"showDialog": "ダイアログを表示",
|
|
24
|
-
"showNotification": "
|
|
24
|
+
"showNotification": "noti-better"
|
|
25
25
|
},
|
|
26
26
|
"option": {
|
|
27
27
|
"topRight": "右上 (Top Right)",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"timeout": "例: 3 または [msg.timeout]",
|
|
41
41
|
"highlight": "例: #ff0000 または red",
|
|
42
42
|
"customIcon": "例: fa-bell, fa-check",
|
|
43
|
-
"ok": "
|
|
44
|
-
"cancel": "
|
|
43
|
+
"ok": "例: Ok, 確定",
|
|
44
|
+
"cancel": "例: Cancel, 中止",
|
|
45
45
|
"promptDefault": "初期入力値(任意)",
|
|
46
46
|
"promptPlaceholder": "プレースホルダー(任意)",
|
|
47
47
|
"className": "[msg.className]",
|
|
48
|
-
"topic": "[msg.topic]",
|
|
48
|
+
"topic": "[msg.topic] またはカスタムタイトル",
|
|
49
49
|
"name": "ノード名"
|
|
50
50
|
},
|
|
51
51
|
"section": {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"noti-better": {
|
|
3
|
+
"paletteLabel": "noti-better",
|
|
4
|
+
"label": {
|
|
5
|
+
"position": "布局位置",
|
|
6
|
+
"notificationType": "通知类型",
|
|
7
|
+
"displayTime": "显示时间 (秒)",
|
|
8
|
+
"highlight": "边框颜色",
|
|
9
|
+
"showIcon": "显示图标",
|
|
10
|
+
"customIcon": "自定义图标",
|
|
11
|
+
"playSound": "播放提示音效",
|
|
12
|
+
"showCountdown": "显示倒计时进度条",
|
|
13
|
+
"preserveCase": "保留按钮原始大小写 (不强制大写)",
|
|
14
|
+
"sendall": "发送至所有浏览器会话",
|
|
15
|
+
"ok": "确认按钮标签",
|
|
16
|
+
"cancel": "取消按钮标签",
|
|
17
|
+
"promptDefault": "默认输入文本",
|
|
18
|
+
"promptPlaceholder": "输入框提示字",
|
|
19
|
+
"raw": "允许 msg.payload 中的原始 HTML / JavaScript",
|
|
20
|
+
"className": "CSS 类名",
|
|
21
|
+
"topic": "主题标题",
|
|
22
|
+
"name": "节点名称",
|
|
23
|
+
"showDialog": "显示对话框",
|
|
24
|
+
"showNotification": "noti-better"
|
|
25
|
+
},
|
|
26
|
+
"option": {
|
|
27
|
+
"topRight": "右上角 (Top Right)",
|
|
28
|
+
"bottomRight": "右下角 (Bottom Right)",
|
|
29
|
+
"topLeft": "左上角 (Top Left)",
|
|
30
|
+
"bottomLeft": "左下角 (Bottom Left)",
|
|
31
|
+
"dialog": "确认 / 取消 对话框 (Dialog)",
|
|
32
|
+
"prompt": "带文本输入框的对话框 (Prompt)",
|
|
33
|
+
"typeDefault": "默认 (中性)",
|
|
34
|
+
"typeInfo": "ℹ 信息 (蓝色)",
|
|
35
|
+
"typeSuccess": "✓ 成功 (绿色)",
|
|
36
|
+
"typeWarning": "⚠ 警告 (琥珀黄)",
|
|
37
|
+
"typeError": "✕ 错误 (红色)"
|
|
38
|
+
},
|
|
39
|
+
"placeholder": {
|
|
40
|
+
"timeout": "例如 3 或 [msg.timeout]",
|
|
41
|
+
"highlight": "例如 #ff0000 或 red",
|
|
42
|
+
"customIcon": "例如 fa-bell、fa-check",
|
|
43
|
+
"ok": "例如 Ok、确定、Submit",
|
|
44
|
+
"cancel": "例如 Cancel、取消",
|
|
45
|
+
"promptDefault": "可选默认输入值",
|
|
46
|
+
"promptPlaceholder": "文本框内的提示字",
|
|
47
|
+
"className": "[msg.className]",
|
|
48
|
+
"topic": "[msg.topic] 或自定义标题",
|
|
49
|
+
"name": "节点名称"
|
|
50
|
+
},
|
|
51
|
+
"section": {
|
|
52
|
+
"basic": "基本设置",
|
|
53
|
+
"appearance": "外观与样式",
|
|
54
|
+
"dialog": "对话框设置",
|
|
55
|
+
"advanced": "高级与行为设置"
|
|
56
|
+
},
|
|
57
|
+
"tip": {
|
|
58
|
+
"raw": "<b>安全提醒</b>:启用原始 HTML/JavaScript 可能允许执行任意脚本。仅在消息内容来自可信来源时开启此选项。",
|
|
59
|
+
"icon": "请输入 Font Awesome 4 图标名称(例如 fa-bell、fa-shield)。若未自定义图标,系统将依据通知类型自动呈现对应图标。",
|
|
60
|
+
"preserveCase": "勾选后,按钮文本将完全依据您所输入的内容呈现,不再被 Angular Material 强制转换为全大写。"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
File without changes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"paletteLabel": "
|
|
2
|
+
"noti-better": {
|
|
3
|
+
"paletteLabel": "noti-better",
|
|
4
4
|
"label": {
|
|
5
5
|
"position": "佈局位置",
|
|
6
|
-
"notificationType": "通知類型
|
|
6
|
+
"notificationType": "通知類型",
|
|
7
7
|
"displayTime": "顯示時間 (秒)",
|
|
8
8
|
"highlight": "外框顏色",
|
|
9
9
|
"showIcon": "顯示圖示",
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
"showCountdown": "顯示倒數進度條",
|
|
13
13
|
"preserveCase": "保留按鈕原始大小寫 (不強制大寫)",
|
|
14
14
|
"sendall": "發送至所有瀏覽器工作階段",
|
|
15
|
-
"ok": "
|
|
16
|
-
"cancel": "
|
|
17
|
-
"promptDefault": "
|
|
18
|
-
"promptPlaceholder": "
|
|
15
|
+
"ok": "確認按鈕標籤",
|
|
16
|
+
"cancel": "取消按鈕標籤",
|
|
17
|
+
"promptDefault": "預設輸入文字",
|
|
18
|
+
"promptPlaceholder": "輸入框提示字",
|
|
19
19
|
"raw": "允許 msg.payload 中的原始 HTML / JavaScript",
|
|
20
|
-
"className": "
|
|
21
|
-
"topic": "
|
|
20
|
+
"className": "CSS 類別",
|
|
21
|
+
"topic": "主題標題",
|
|
22
22
|
"name": "節點名稱",
|
|
23
23
|
"showDialog": "顯示對話框",
|
|
24
|
-
"showNotification": "
|
|
24
|
+
"showNotification": "進階通知"
|
|
25
25
|
},
|
|
26
26
|
"option": {
|
|
27
27
|
"topRight": "右上角 (Top Right)",
|
|
@@ -40,19 +40,19 @@
|
|
|
40
40
|
"timeout": "例如 3 或 [msg.timeout]",
|
|
41
41
|
"highlight": "例如 #ff0000 或 red",
|
|
42
42
|
"customIcon": "例如 fa-bell、fa-check",
|
|
43
|
-
"ok": "
|
|
44
|
-
"cancel": "
|
|
43
|
+
"ok": "例如 Ok、確定、Submit",
|
|
44
|
+
"cancel": "例如 Cancel、取消",
|
|
45
45
|
"promptDefault": "可選預設輸入值",
|
|
46
46
|
"promptPlaceholder": "文字框內的提示字",
|
|
47
47
|
"className": "[msg.className]",
|
|
48
|
-
"topic": "[msg.topic]",
|
|
48
|
+
"topic": "[msg.topic] 或自訂標題",
|
|
49
49
|
"name": "節點名稱"
|
|
50
50
|
},
|
|
51
51
|
"section": {
|
|
52
52
|
"basic": "基本設定",
|
|
53
53
|
"appearance": "外觀與樣式",
|
|
54
54
|
"dialog": "對話框設定",
|
|
55
|
-
"advanced": "
|
|
55
|
+
"advanced": "進階與行為設定"
|
|
56
56
|
},
|
|
57
57
|
"tip": {
|
|
58
58
|
"raw": "<b>安全提醒</b>:啟用原始 HTML/JavaScript 可能允許執行任意腳本。僅在訊息內容來自可信來源時開啟此選項。",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-notification-better",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "An enhanced notification and dialog node for Node-RED Dashboard supporting exact button casing, preset notification levels, audio alerts, countdown progress bar, and multi-language UI.",
|
|
5
5
|
"main": "ui_notification.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,12 +14,13 @@
|
|
|
14
14
|
"dialog",
|
|
15
15
|
"prompt",
|
|
16
16
|
"alert",
|
|
17
|
+
"noti-better",
|
|
17
18
|
"ui"
|
|
18
19
|
],
|
|
19
20
|
"node-red": {
|
|
20
21
|
"version": ">=1.0.0",
|
|
21
22
|
"nodes": {
|
|
22
|
-
"
|
|
23
|
+
"noti-better": "ui_notification.js"
|
|
23
24
|
}
|
|
24
25
|
},
|
|
25
26
|
"author": "",
|
package/ui_notification.html
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
|
-
RED.nodes.registerType('
|
|
2
|
+
RED.nodes.registerType('noti-better', {
|
|
3
3
|
category: (RED._("node-red-dashboard/ui_base:ui_base.label.category") || 'dashboard'),
|
|
4
4
|
color: 'rgb(119, 198, 204)',
|
|
5
5
|
defaults: {
|
|
@@ -28,10 +28,24 @@
|
|
|
28
28
|
align: "right",
|
|
29
29
|
icon: "font-awesome/fa-bell",
|
|
30
30
|
paletteLabel: function() {
|
|
31
|
-
|
|
31
|
+
try {
|
|
32
|
+
var text = this._("noti-better.paletteLabel");
|
|
33
|
+
return (text && text.indexOf(".") === -1 && text.indexOf("noti-better") === -1) ? text : "noti-better";
|
|
34
|
+
} catch(e) {
|
|
35
|
+
return "noti-better";
|
|
36
|
+
}
|
|
32
37
|
},
|
|
33
38
|
label: function() {
|
|
34
|
-
|
|
39
|
+
if (this.name) { return this.name; }
|
|
40
|
+
var isDlg = (this.position === "prompt" || this.position === "dialog");
|
|
41
|
+
var fallback = isDlg ? "顯示對話框" : "進階通知";
|
|
42
|
+
try {
|
|
43
|
+
var key = isDlg ? "noti-better.label.showDialog" : "noti-better.label.showNotification";
|
|
44
|
+
var text = this._(key);
|
|
45
|
+
return (text && text.indexOf(".") === -1 && text !== key) ? text : fallback;
|
|
46
|
+
} catch(e) {
|
|
47
|
+
return fallback;
|
|
48
|
+
}
|
|
35
49
|
},
|
|
36
50
|
labelStyle: function() {
|
|
37
51
|
return this.name ? "node_label_italic" : "";
|
|
@@ -92,7 +106,7 @@
|
|
|
92
106
|
}
|
|
93
107
|
}).trigger("change");
|
|
94
108
|
|
|
95
|
-
//
|
|
109
|
+
// 安全警語聯動
|
|
96
110
|
$("#node-input-raw").on("change", function() {
|
|
97
111
|
if ($(this).is(":checked")) {
|
|
98
112
|
$("#node-tip-raw-warning").slideDown(200);
|
|
@@ -113,171 +127,227 @@
|
|
|
113
127
|
</script>
|
|
114
128
|
|
|
115
129
|
<style>
|
|
116
|
-
.nr-
|
|
117
|
-
font-weight:
|
|
118
|
-
|
|
119
|
-
margin-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
color: #333;
|
|
125
|
-
display: flex;
|
|
126
|
-
align-items: center;
|
|
127
|
-
gap: 8px;
|
|
130
|
+
.nr-noti-section-title {
|
|
131
|
+
font-weight: bold;
|
|
132
|
+
margin-top: 16px;
|
|
133
|
+
margin-bottom: 10px;
|
|
134
|
+
padding-bottom: 4px;
|
|
135
|
+
border-bottom: 2px solid #77c6cc;
|
|
136
|
+
display: inline-block;
|
|
137
|
+
letter-spacing: 0.5px;
|
|
128
138
|
}
|
|
129
|
-
.nr-
|
|
139
|
+
.nr-noti-tip-box {
|
|
130
140
|
margin: 10px 0;
|
|
131
|
-
padding:
|
|
132
|
-
background-color:
|
|
141
|
+
padding: 8px 12px;
|
|
142
|
+
background-color: rgba(255, 184, 0, 0.15);
|
|
133
143
|
border-left: 4px solid #ffb800;
|
|
134
|
-
border-radius:
|
|
144
|
+
border-radius: 3px;
|
|
135
145
|
font-size: 12px;
|
|
136
146
|
line-height: 1.5;
|
|
137
|
-
color: #665200;
|
|
138
147
|
}
|
|
139
148
|
</style>
|
|
140
149
|
|
|
141
|
-
<script type="text/html" data-template-name="
|
|
150
|
+
<script type="text/html" data-template-name="noti-better">
|
|
142
151
|
<!-- 基本設定區塊 -->
|
|
143
|
-
<div class="
|
|
144
|
-
<
|
|
152
|
+
<div class="form-row">
|
|
153
|
+
<span class="nr-noti-section-title">
|
|
154
|
+
<i class="fa fa-sliders"></i> <span data-i18n="noti-better.section.basic">基本設定</span>
|
|
155
|
+
</span>
|
|
145
156
|
</div>
|
|
146
157
|
|
|
147
158
|
<div class="form-row">
|
|
148
|
-
<label for="node-input-position"><i class="fa fa-th-large"></i> <span data-i18n="
|
|
159
|
+
<label for="node-input-position"><i class="fa fa-th-large"></i> <span data-i18n="noti-better.label.position">佈局位置</span></label>
|
|
149
160
|
<select id="node-input-position" style="width:70%;">
|
|
150
|
-
<option value="top right" data-i18n="
|
|
151
|
-
<option value="bottom right" data-i18n="
|
|
152
|
-
<option value="top left" data-i18n="
|
|
153
|
-
<option value="bottom left" data-i18n="
|
|
154
|
-
<option value="dialog" data-i18n="
|
|
155
|
-
<option value="prompt" data-i18n="
|
|
161
|
+
<option value="top right" data-i18n="noti-better.option.topRight">右上角 (Top Right)</option>
|
|
162
|
+
<option value="bottom right" data-i18n="noti-better.option.bottomRight">右下角 (Bottom Right)</option>
|
|
163
|
+
<option value="top left" data-i18n="noti-better.option.topLeft">左上角 (Top Left)</option>
|
|
164
|
+
<option value="bottom left" data-i18n="noti-better.option.bottomLeft">左下角 (Bottom Left)</option>
|
|
165
|
+
<option value="dialog" data-i18n="noti-better.option.dialog">確認 / 取消 對話框 (Dialog)</option>
|
|
166
|
+
<option value="prompt" data-i18n="noti-better.option.prompt">帶文字輸入框的對話框 (Prompt)</option>
|
|
156
167
|
</select>
|
|
157
168
|
</div>
|
|
158
169
|
|
|
159
170
|
<div class="form-row">
|
|
160
|
-
<label for="node-input-notificationType"><i class="fa fa-tag"></i> <span data-i18n="
|
|
171
|
+
<label for="node-input-notificationType"><i class="fa fa-tag"></i> <span data-i18n="noti-better.label.notificationType">通知類型</span></label>
|
|
161
172
|
<select id="node-input-notificationType" style="width:70%;">
|
|
162
|
-
<option value="default" data-i18n="
|
|
163
|
-
<option value="info" data-i18n="
|
|
164
|
-
<option value="success" data-i18n="
|
|
165
|
-
<option value="warning" data-i18n="
|
|
166
|
-
<option value="error" data-i18n="
|
|
173
|
+
<option value="default" data-i18n="noti-better.option.typeDefault">預設 (中性)</option>
|
|
174
|
+
<option value="info" data-i18n="noti-better.option.typeInfo">ℹ 資訊 (藍色)</option>
|
|
175
|
+
<option value="success" data-i18n="noti-better.option.typeSuccess">✓ 成功 (綠色)</option>
|
|
176
|
+
<option value="warning" data-i18n="noti-better.option.typeWarning">⚠ 警告 (琥珀黃)</option>
|
|
177
|
+
<option value="error" data-i18n="noti-better.option.typeError">✕ 錯誤 (紅色)</option>
|
|
167
178
|
</select>
|
|
168
179
|
</div>
|
|
169
180
|
|
|
170
181
|
<div class="form-row">
|
|
171
|
-
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="
|
|
172
|
-
<input type="text" id="node-input-topic" data-i18n="[placeholder]
|
|
182
|
+
<label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="noti-better.label.topic">主題標題</span></label>
|
|
183
|
+
<input type="text" id="node-input-topic" placeholder="[msg.topic] 或自訂標題" data-i18n="[placeholder]noti-better.placeholder.topic">
|
|
173
184
|
</div>
|
|
174
185
|
|
|
175
186
|
<!-- 浮動通知專用設定 (Timeout, 進度條等) -->
|
|
176
187
|
<div id="section-toast-settings">
|
|
177
188
|
<div class="form-row">
|
|
178
|
-
<label for="node-input-displayTime"><i class="fa fa-clock-o"></i> <span data-i18n="
|
|
179
|
-
<input type="text" id="node-input-displayTime" data-i18n="[placeholder]
|
|
189
|
+
<label for="node-input-displayTime"><i class="fa fa-clock-o"></i> <span data-i18n="noti-better.label.displayTime">顯示時間 (秒)</span></label>
|
|
190
|
+
<input type="text" id="node-input-displayTime" placeholder="例如 3 或 [msg.timeout]" data-i18n="[placeholder]noti-better.placeholder.timeout">
|
|
180
191
|
</div>
|
|
181
192
|
<div class="form-row">
|
|
182
193
|
<label style="width:auto;" for="node-input-showCountdown">
|
|
183
194
|
<input type="checkbox" id="node-input-showCountdown" style="display:inline-block; width:auto; vertical-align:baseline; margin-right:6px;">
|
|
184
|
-
<span data-i18n="
|
|
195
|
+
<span data-i18n="noti-better.label.showCountdown">顯示倒數進度條</span>
|
|
185
196
|
</label>
|
|
186
197
|
</div>
|
|
187
198
|
</div>
|
|
188
199
|
|
|
189
200
|
<!-- 外觀與圖示設定區塊 -->
|
|
190
|
-
<div class="
|
|
191
|
-
<
|
|
201
|
+
<div class="form-row">
|
|
202
|
+
<span class="nr-noti-section-title">
|
|
203
|
+
<i class="fa fa-paint-brush"></i> <span data-i18n="noti-better.section.appearance">外觀與樣式</span>
|
|
204
|
+
</span>
|
|
192
205
|
</div>
|
|
193
206
|
|
|
194
207
|
<div class="form-row">
|
|
195
|
-
<label for="node-input-highlight"><i class="fa fa-square-o"></i> <span data-i18n="
|
|
196
|
-
<input type="text" id="node-input-highlight" data-i18n="[placeholder]
|
|
208
|
+
<label for="node-input-highlight"><i class="fa fa-square-o"></i> <span data-i18n="noti-better.label.highlight">外框顏色</span></label>
|
|
209
|
+
<input type="text" id="node-input-highlight" placeholder="例如 #ff0000 或 red" data-i18n="[placeholder]noti-better.placeholder.highlight">
|
|
197
210
|
</div>
|
|
198
211
|
|
|
199
212
|
<div class="form-row">
|
|
200
213
|
<label style="width:auto;" for="node-input-showIcon">
|
|
201
214
|
<input type="checkbox" id="node-input-showIcon" style="display:inline-block; width:auto; vertical-align:baseline; margin-right:6px;">
|
|
202
|
-
<span data-i18n="
|
|
215
|
+
<span data-i18n="noti-better.label.showIcon">顯示圖示</span>
|
|
203
216
|
</label>
|
|
204
217
|
</div>
|
|
205
218
|
|
|
206
219
|
<div class="form-row" id="node-row-customIcon">
|
|
207
|
-
<label for="node-input-customIcon"><i class="fa fa-font-awesome"></i> <span data-i18n="
|
|
208
|
-
<input type="text" id="node-input-customIcon" data-i18n="[placeholder]
|
|
220
|
+
<label for="node-input-customIcon"><i class="fa fa-font-awesome"></i> <span data-i18n="noti-better.label.customIcon">自訂圖示</span></label>
|
|
221
|
+
<input type="text" id="node-input-customIcon" placeholder="例如 fa-bell、fa-check" data-i18n="[placeholder]noti-better.placeholder.customIcon">
|
|
209
222
|
</div>
|
|
210
223
|
|
|
211
224
|
<div class="form-row">
|
|
212
|
-
<label for="node-input-className"><i class="fa fa-code"></i> <span data-i18n="
|
|
213
|
-
<input type="text" id="node-input-className" data-i18n="[placeholder]
|
|
225
|
+
<label for="node-input-className"><i class="fa fa-code"></i> <span data-i18n="noti-better.label.className">CSS 類別</span></label>
|
|
226
|
+
<input type="text" id="node-input-className" placeholder="[msg.className]" data-i18n="[placeholder]noti-better.placeholder.className">
|
|
214
227
|
</div>
|
|
215
228
|
|
|
216
229
|
<!-- 對話框專用設定 (按鈕與大小寫) -->
|
|
217
230
|
<div id="section-dialog-settings" style="display:none;">
|
|
218
|
-
<div class="
|
|
219
|
-
<
|
|
231
|
+
<div class="form-row">
|
|
232
|
+
<span class="nr-noti-section-title">
|
|
233
|
+
<i class="fa fa-commenting-o"></i> <span data-i18n="noti-better.section.dialog">對話框設定</span>
|
|
234
|
+
</span>
|
|
220
235
|
</div>
|
|
221
236
|
|
|
222
237
|
<div class="form-row">
|
|
223
|
-
<label for="node-input-ok"><i class="fa fa-check"></i> <span data-i18n="
|
|
224
|
-
<input type="text" id="node-input-ok" data-i18n="[placeholder]
|
|
238
|
+
<label for="node-input-ok"><i class="fa fa-check"></i> <span data-i18n="noti-better.label.ok">確認按鈕標籤</span></label>
|
|
239
|
+
<input type="text" id="node-input-ok" placeholder="例如 Ok、確定、Submit" data-i18n="[placeholder]noti-better.placeholder.ok">
|
|
225
240
|
</div>
|
|
226
241
|
|
|
227
242
|
<div class="form-row">
|
|
228
|
-
<label for="node-input-cancel"><i class="fa fa-times"></i> <span data-i18n="
|
|
229
|
-
<input type="text" id="node-input-cancel" data-i18n="[placeholder]
|
|
243
|
+
<label for="node-input-cancel"><i class="fa fa-times"></i> <span data-i18n="noti-better.label.cancel">取消按鈕標籤</span></label>
|
|
244
|
+
<input type="text" id="node-input-cancel" placeholder="例如 Cancel、取消" data-i18n="[placeholder]noti-better.placeholder.cancel">
|
|
230
245
|
</div>
|
|
231
246
|
|
|
232
247
|
<div id="node-dialog-prompt-fields" style="display:none;">
|
|
233
248
|
<div class="form-row">
|
|
234
|
-
<label for="node-input-promptDefault"><i class="fa fa-pencil-square-o"></i> <span data-i18n="
|
|
235
|
-
<input type="text" id="node-input-promptDefault" data-i18n="[placeholder]
|
|
249
|
+
<label for="node-input-promptDefault"><i class="fa fa-pencil-square-o"></i> <span data-i18n="noti-better.label.promptDefault">預設輸入文字</span></label>
|
|
250
|
+
<input type="text" id="node-input-promptDefault" placeholder="可選預設輸入值" data-i18n="[placeholder]noti-better.placeholder.promptDefault">
|
|
236
251
|
</div>
|
|
237
252
|
<div class="form-row">
|
|
238
|
-
<label for="node-input-promptPlaceholder"><i class="fa fa-i-cursor"></i> <span data-i18n="
|
|
239
|
-
<input type="text" id="node-input-promptPlaceholder" data-i18n="[placeholder]
|
|
253
|
+
<label for="node-input-promptPlaceholder"><i class="fa fa-i-cursor"></i> <span data-i18n="noti-better.label.promptPlaceholder">輸入框提示字</span></label>
|
|
254
|
+
<input type="text" id="node-input-promptPlaceholder" placeholder="輸入框內的提示字 (Placeholder)" data-i18n="[placeholder]noti-better.placeholder.promptPlaceholder">
|
|
240
255
|
</div>
|
|
241
256
|
</div>
|
|
242
257
|
|
|
243
258
|
<div class="form-row">
|
|
244
259
|
<label style="width:auto;" for="node-input-preserveCase">
|
|
245
260
|
<input type="checkbox" id="node-input-preserveCase" style="display:inline-block; width:auto; vertical-align:baseline; margin-right:6px;">
|
|
246
|
-
<span data-i18n="
|
|
261
|
+
<span data-i18n="noti-better.label.preserveCase">保留按鈕原始大小寫 (不強制大寫)</span>
|
|
247
262
|
</label>
|
|
248
263
|
</div>
|
|
249
264
|
</div>
|
|
250
265
|
|
|
251
266
|
<!-- 行為與進階設定區塊 -->
|
|
252
|
-
<div class="
|
|
253
|
-
<
|
|
267
|
+
<div class="form-row">
|
|
268
|
+
<span class="nr-noti-section-title">
|
|
269
|
+
<i class="fa fa-cogs"></i> <span data-i18n="noti-better.section.advanced">進階與行為設定</span>
|
|
270
|
+
</span>
|
|
254
271
|
</div>
|
|
255
272
|
|
|
256
273
|
<div class="form-row">
|
|
257
274
|
<label style="width:auto;" for="node-input-playSound">
|
|
258
275
|
<input type="checkbox" id="node-input-playSound" style="display:inline-block; width:auto; vertical-align:baseline; margin-right:6px;">
|
|
259
|
-
<span data-i18n="
|
|
276
|
+
<span data-i18n="noti-better.label.playSound">播放提示音效</span>
|
|
260
277
|
</label>
|
|
261
278
|
</div>
|
|
262
279
|
|
|
263
280
|
<div class="form-row">
|
|
264
281
|
<label style="width:auto;" for="node-input-sendall">
|
|
265
282
|
<input type="checkbox" id="node-input-sendall" style="display:inline-block; width:auto; vertical-align:baseline; margin-right:6px;">
|
|
266
|
-
<span data-i18n="
|
|
283
|
+
<span data-i18n="noti-better.label.sendall">發送至所有瀏覽器工作階段</span>
|
|
267
284
|
</label>
|
|
268
285
|
</div>
|
|
269
286
|
|
|
270
287
|
<div class="form-row">
|
|
271
288
|
<label style="width:auto;" for="node-input-raw">
|
|
272
289
|
<input type="checkbox" id="node-input-raw" style="display:inline-block; width:auto; vertical-align:baseline; margin-right:6px;">
|
|
273
|
-
<span data-i18n="
|
|
290
|
+
<span data-i18n="noti-better.label.raw">允許 msg.payload 中的原始 HTML / JavaScript</span>
|
|
274
291
|
</label>
|
|
275
292
|
</div>
|
|
276
293
|
|
|
277
|
-
<div id="node-tip-raw-warning" class="nr-
|
|
294
|
+
<div id="node-tip-raw-warning" class="nr-noti-tip-box" style="display:none;" data-i18n="[html]noti-better.tip.raw">
|
|
295
|
+
<b>安全提醒</b>:啟用原始 HTML/JavaScript 可能允許執行任意腳本。僅在訊息內容來自可信來源時開啟此選項。
|
|
296
|
+
</div>
|
|
278
297
|
|
|
279
298
|
<div class="form-row" style="margin-top:14px;">
|
|
280
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="
|
|
281
|
-
<input type="text" id="node-input-name" data-i18n="[placeholder]
|
|
299
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="noti-better.label.name">節點名稱</span></label>
|
|
300
|
+
<input type="text" id="node-input-name" placeholder="節點名稱" data-i18n="[placeholder]noti-better.placeholder.name">
|
|
282
301
|
</div>
|
|
283
302
|
</script>
|
|
303
|
+
|
|
304
|
+
<script type="text/html" data-help-name="noti-better">
|
|
305
|
+
<p>專為 <b>Node-RED Dashboard</b> 量身打造的強化版通知 (Notification / Toast) 與互動式對話框 (Dialog) 節點。</p>
|
|
306
|
+
|
|
307
|
+
<h3>核心特色</h3>
|
|
308
|
+
<ul>
|
|
309
|
+
<li><b>忠實保留按鈕大小寫</b>:徹底解除 Angular Material 強制大寫的限制,輸入「Ok」即顯示「Ok」,大小寫百分之百精確呈現。</li>
|
|
310
|
+
<li><b>通知等級預設</b>:內建 Info(資訊)、Success(成功)、Warning(警告)、Error(錯誤)四種視覺主題與自動圖示。</li>
|
|
311
|
+
<li><b>音效提醒</b>:內建 Web Audio API 音效支援,可發出清脆的提示聲。</li>
|
|
312
|
+
<li><b>豐富的自訂性</b>:支援原生 HTML / JavaScript、倒數進度條、自訂外框顏色與圖示。</li>
|
|
313
|
+
</ul>
|
|
314
|
+
|
|
315
|
+
<h3>輸入屬性 (Inputs)</h3>
|
|
316
|
+
<dl class="message-properties">
|
|
317
|
+
<dt>payload <span class="property-type">字串 | 物件</span></dt>
|
|
318
|
+
<dd>顯示在彈出框中的主要內容。若啟用「允許原始 HTML / JS」,將忠實渲染 HTML 與動畫標籤。</dd>
|
|
319
|
+
|
|
320
|
+
<dt class="optional">topic <span class="property-type">字串</span></dt>
|
|
321
|
+
<dd>通知或對話框的頂部標題。</dd>
|
|
322
|
+
|
|
323
|
+
<dt class="optional">timeout <span class="property-type">數值</span></dt>
|
|
324
|
+
<dd>自動關閉的顯示秒數(預設 3 秒),設為 0 會立即關閉。</dd>
|
|
325
|
+
|
|
326
|
+
<dt class="optional">notificationType <span class="property-type">字串</span></dt>
|
|
327
|
+
<dd>通知等級,可指定為 <code>default</code>、<code>info</code>、<code>success</code>、<code>warning</code> 或 <code>error</code>。</dd>
|
|
328
|
+
|
|
329
|
+
<dt class="optional">ok <span class="property-type">字串</span></dt>
|
|
330
|
+
<dd>確認按鈕文字(完全保留原始大小寫)。</dd>
|
|
331
|
+
|
|
332
|
+
<dt class="optional">cancel <span class="property-type">字串</span></dt>
|
|
333
|
+
<dd>取消按鈕文字(完全保留原始大小寫)。</dd>
|
|
334
|
+
|
|
335
|
+
<dt class="optional">highlight <span class="property-type">字串</span></dt>
|
|
336
|
+
<dd>外框高亮顏色(例如 <code>#2ecc71</code> 或 <code>green</code>)。</dd>
|
|
337
|
+
|
|
338
|
+
<dt class="optional">icon <span class="property-type">字串</span></dt>
|
|
339
|
+
<dd>自訂 Font Awesome 圖示名稱(例如 <code>fa-bell</code>)。</dd>
|
|
340
|
+
|
|
341
|
+
<dt class="optional">playSound <span class="property-type">布林值</span></dt>
|
|
342
|
+
<dd>是否在彈出通知時播放提示音效。</dd>
|
|
343
|
+
|
|
344
|
+
<dt class="optional">socketid <span class="property-type">字串</span></dt>
|
|
345
|
+
<dd>若未勾選廣播至所有工作階段,可指定單一瀏覽器連線的 Session ID。</dd>
|
|
346
|
+
</dl>
|
|
347
|
+
|
|
348
|
+
<h3>輸出屬性 (Outputs)</h3>
|
|
349
|
+
<dl class="message-properties">
|
|
350
|
+
<dt>payload <span class="property-type">字串</span></dt>
|
|
351
|
+
<dd>當佈局設為 <b>Dialog</b>(確認對話框)或 <b>Prompt</b>(文字輸入對話框)時,使用者點擊或輸入確認後的結果將由輸出點發送。</dd>
|
|
352
|
+
</dl>
|
|
353
|
+
</script>
|
package/ui_notification.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* node-red-contrib-notification-better
|
|
3
|
-
*
|
|
2
|
+
* node-red-contrib-notification-better (noti-better)
|
|
3
|
+
* 專為 Node-RED Dashboard 設計的進階通知與互動對話框節點
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
module.exports = function(RED) {
|
|
@@ -11,39 +11,39 @@ module.exports = function(RED) {
|
|
|
11
11
|
try {
|
|
12
12
|
ui = require("node-red-dashboard")(RED);
|
|
13
13
|
} catch (e2) {
|
|
14
|
-
RED.log.warn("
|
|
14
|
+
RED.log.warn("noti-better: 找不到 node-red-dashboard,請確保已安裝該套件。");
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// 全域 CSS
|
|
18
|
+
// 全域 CSS 注入:徹底消除 Angular Material 的強制大寫,並為深淺主題提供美化
|
|
19
19
|
var globalStyleInjected = false;
|
|
20
20
|
var betterNotificationCSS = `
|
|
21
|
-
<style id="nr-
|
|
22
|
-
/*
|
|
21
|
+
<style id="nr-noti-better-styles">
|
|
22
|
+
/* 徹底解除對話框與通知按鈕強制大寫的限制,忠實依輸入原樣呈現 */
|
|
23
23
|
.nr-dashboard-dialog .md-button,
|
|
24
24
|
.nr-dashboard-dialog .md-confirm-button,
|
|
25
25
|
.nr-dashboard-dialog .md-cancel-button,
|
|
26
26
|
.nr-dashboard-dialog button,
|
|
27
|
-
.nr-better
|
|
28
|
-
.nr-
|
|
27
|
+
.nr-noti-better .md-button,
|
|
28
|
+
.nr-noti-dialog .md-button,
|
|
29
29
|
.nr-preserve-case .md-button,
|
|
30
|
-
md-dialog.nr-better
|
|
30
|
+
md-dialog.nr-noti-better .md-button,
|
|
31
31
|
md-dialog.nr-preserve-case .md-button,
|
|
32
|
-
md-toast.nr-better
|
|
32
|
+
md-toast.nr-noti-better .md-button {
|
|
33
33
|
text-transform: none !important;
|
|
34
34
|
font-weight: 500 !important;
|
|
35
35
|
letter-spacing: 0.3px !important;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/* 現代化通知卡片外觀增強 */
|
|
39
|
-
md-toast.nr-better
|
|
39
|
+
md-toast.nr-noti-better .md-toast-content {
|
|
40
40
|
border-radius: 8px !important;
|
|
41
|
-
box-shadow: 0 4px
|
|
41
|
+
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.28) !important;
|
|
42
42
|
padding: 12px 18px !important;
|
|
43
43
|
font-size: 14px !important;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/*
|
|
46
|
+
/* 通知等級外框主題色彩 */
|
|
47
47
|
.nr-type-info {
|
|
48
48
|
border-left: 6px solid #2196F3 !important;
|
|
49
49
|
}
|
|
@@ -87,7 +87,7 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
87
87
|
if (!ui || globalStyleInjected) { return; }
|
|
88
88
|
try {
|
|
89
89
|
ui.emit("update-value", {
|
|
90
|
-
id: "
|
|
90
|
+
id: "nr_noti_better_global_style",
|
|
91
91
|
msg: {
|
|
92
92
|
templateScope: "global",
|
|
93
93
|
template: betterNotificationCSS
|
|
@@ -95,7 +95,7 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
95
95
|
});
|
|
96
96
|
globalStyleInjected = true;
|
|
97
97
|
} catch (err) {
|
|
98
|
-
//
|
|
98
|
+
// socket 未就緒時忽略,後續 input 會再次觸發
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -104,11 +104,11 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
104
104
|
var node = this;
|
|
105
105
|
|
|
106
106
|
if (!ui) {
|
|
107
|
-
node.error("
|
|
107
|
+
node.error("noti-better 需要依賴 node-red-dashboard,請先在 Palette 管理員安裝 node-red-dashboard。");
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
//
|
|
111
|
+
// 解析基本與進階設定
|
|
112
112
|
if (config.hasOwnProperty("displayTime") && (config.displayTime.length > 0)) {
|
|
113
113
|
try {
|
|
114
114
|
this.displayTime = parseFloat(config.displayTime) * 1000;
|
|
@@ -137,7 +137,7 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
137
137
|
this.className = config.className || "";
|
|
138
138
|
this.topic = config.topic || "";
|
|
139
139
|
|
|
140
|
-
//
|
|
140
|
+
// 節點初始化時嘗試注入全域樣式
|
|
141
141
|
injectGlobalStyles();
|
|
142
142
|
|
|
143
143
|
var done = ui.add({
|
|
@@ -152,7 +152,7 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
152
152
|
}
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
//
|
|
155
|
+
// 預設等級顏色與圖示映射
|
|
156
156
|
var typePresets = {
|
|
157
157
|
"info": {
|
|
158
158
|
color: "#2196F3",
|
|
@@ -182,7 +182,7 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
182
182
|
};
|
|
183
183
|
|
|
184
184
|
node.on('input', function(msg) {
|
|
185
|
-
//
|
|
185
|
+
// 處理 input 時確保樣式注入
|
|
186
186
|
injectGlobalStyles();
|
|
187
187
|
|
|
188
188
|
if (node.sendall === true && !msg.socketid) {
|
|
@@ -204,7 +204,7 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
204
204
|
var currentType = (msg.notificationType || msg.status || msg.level || node.notificationType || "default").toLowerCase();
|
|
205
205
|
var preset = typePresets[currentType] || typePresets["default"];
|
|
206
206
|
|
|
207
|
-
//
|
|
207
|
+
// 邊框高亮顏色(支援節點設定與動態輸入)
|
|
208
208
|
var currentHighlight = msg.highlight || msg.border || node.highlight || preset.color;
|
|
209
209
|
|
|
210
210
|
// 圖示判定
|
|
@@ -241,11 +241,11 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
241
241
|
var playAudio = msg.hasOwnProperty("playSound") ? Boolean(msg.playSound) : Boolean(node.playSound);
|
|
242
242
|
var soundScript = "";
|
|
243
243
|
if (playAudio) {
|
|
244
|
-
// 利用瀏覽器內建 Web Audio API
|
|
244
|
+
// 利用瀏覽器內建 Web Audio API 合成提示聲,無須外部音訊檔
|
|
245
245
|
soundScript = `<script>(function(){try{var A=window.AudioContext||window.webkitAudioContext;if(A){var c=new A(),o=c.createOscillator(),g=c.createGain();o.type='sine';o.frequency.setValueAtTime(${currentType==='error'?330:587},c.currentTime);o.frequency.exponentialRampToValueAtTime(${currentType==='error'?220:880},c.currentTime+0.2);g.gain.setValueAtTime(0.15,c.currentTime);g.gain.exponentialRampToValueAtTime(0.01,c.currentTime+0.25);o.connect(g);g.connect(c.destination);o.start();o.stop(c.currentTime+0.25);}}catch(e){}})();</script>`;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
// 當啟用 raw
|
|
248
|
+
// 當啟用 raw 時組合圖示、音效與倒數進度條
|
|
249
249
|
if (isRaw) {
|
|
250
250
|
var iconHtml = (node.showIcon && currentIcon) ? `<i class="fa ${currentIcon}" style="margin-right:8px; vertical-align:middle;"></i> ` : "";
|
|
251
251
|
var progressHtml = (!isDialog && node.showCountdown) ? `<div class="nr-toast-progress-wrap"><div class="nr-toast-progress-bar" style="animation-duration:${dt}ms;"></div></div>` : "";
|
|
@@ -253,12 +253,12 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
// 組合 CSS 類別
|
|
256
|
-
var classList = ["nr-better
|
|
256
|
+
var classList = ["nr-noti-better"];
|
|
257
257
|
if (node.preserveCase) {
|
|
258
258
|
classList.push("nr-preserve-case");
|
|
259
259
|
}
|
|
260
260
|
if (isDialog) {
|
|
261
|
-
classList.push("nr-
|
|
261
|
+
classList.push("nr-noti-dialog");
|
|
262
262
|
}
|
|
263
263
|
if (preset.className) {
|
|
264
264
|
classList.push(preset.className);
|
|
@@ -293,5 +293,5 @@ md-toast.nr-better-notification .md-toast-content {
|
|
|
293
293
|
node.on("close", done);
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
RED.nodes.registerType("
|
|
296
|
+
RED.nodes.registerType("noti-better", ToastNode);
|
|
297
297
|
};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<script type="text/html" data-help-name="ui_notification_better">
|
|
2
|
-
<p>An enhanced notification and dialog node designed for <b>Node-RED Dashboard</b>.</p>
|
|
3
|
-
|
|
4
|
-
<h3>Features</h3>
|
|
5
|
-
<ul>
|
|
6
|
-
<li><b>Exact Button Case</b>: Disables Angular Material's forced uppercase styling, displaying button text exactly as typed.</li>
|
|
7
|
-
<li><b>Levels & Types</b>: Built-in presets for Info, Success, Warning, and Error with automatic styling and icons.</li>
|
|
8
|
-
<li><b>Audio Alerts</b>: Built-in sound chime support via Web Audio API.</li>
|
|
9
|
-
<li><b>Rich Customization</b>: Raw HTML/JS formatting, custom icons, border highlight, and countdown bar.</li>
|
|
10
|
-
</ul>
|
|
11
|
-
|
|
12
|
-
<h3>Inputs</h3>
|
|
13
|
-
<dl class="message-properties">
|
|
14
|
-
<dt>payload <span class="property-type">string | object</span></dt>
|
|
15
|
-
<dd>The message body to display. If <i>Accept raw HTML/JS</i> is enabled, raw HTML tags will be rendered directly.</dd>
|
|
16
|
-
|
|
17
|
-
<dt class="optional">topic <span class="property-type">string</span></dt>
|
|
18
|
-
<dd>The notification or dialog title.</dd>
|
|
19
|
-
|
|
20
|
-
<dt class="optional">timeout <span class="property-type">number</span></dt>
|
|
21
|
-
<dd>Duration in seconds before auto-dismissal (defaults to 3s). Set to 0 to dismiss immediately.</dd>
|
|
22
|
-
|
|
23
|
-
<dt class="optional">notificationType <span class="property-type">string</span></dt>
|
|
24
|
-
<dd>One of <code>default</code>, <code>info</code>, <code>success</code>, <code>warning</code>, or <code>error</code>.</dd>
|
|
25
|
-
|
|
26
|
-
<dt class="optional">ok <span class="property-type">string</span></dt>
|
|
27
|
-
<dd>Custom text for the primary confirmation button (casing preserved).</dd>
|
|
28
|
-
|
|
29
|
-
<dt class="optional">cancel <span class="property-type">string</span></dt>
|
|
30
|
-
<dd>Custom text for the cancel button (casing preserved).</dd>
|
|
31
|
-
|
|
32
|
-
<dt class="optional">highlight <span class="property-type">string</span></dt>
|
|
33
|
-
<dd>Border highlight color (e.g. <code>#2ecc71</code> or <code>green</code>).</dd>
|
|
34
|
-
|
|
35
|
-
<dt class="optional">icon <span class="property-type">string</span></dt>
|
|
36
|
-
<dd>Font Awesome icon class name (e.g. <code>fa-bell</code>).</dd>
|
|
37
|
-
|
|
38
|
-
<dt class="optional">playSound <span class="property-type">boolean</span></dt>
|
|
39
|
-
<dd>Whether to play an audible chime when triggering the alert.</dd>
|
|
40
|
-
|
|
41
|
-
<dt class="optional">socketid <span class="property-type">string</span></dt>
|
|
42
|
-
<dd>When <i>Send to all browser sessions</i> is disabled, targets this specific client session.</dd>
|
|
43
|
-
</dl>
|
|
44
|
-
|
|
45
|
-
<h3>Outputs</h3>
|
|
46
|
-
<dl class="message-properties">
|
|
47
|
-
<dt>payload <span class="property-type">string</span></dt>
|
|
48
|
-
<dd>When layout is set to <b>Dialog</b> or <b>Prompt</b>, emits the user's action or entered text when closed.</dd>
|
|
49
|
-
</dl>
|
|
50
|
-
</script>
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"ui_notification_better": {
|
|
3
|
-
"paletteLabel": "高級通知",
|
|
4
|
-
"label": {
|
|
5
|
-
"position": "佈局位置",
|
|
6
|
-
"displayTime": "逾時秒數 (秒)",
|
|
7
|
-
"highlight": "邊框顏色",
|
|
8
|
-
"sendall": "發送至所有瀏覽器會話",
|
|
9
|
-
"ok": "默認操作標籤",
|
|
10
|
-
"cancel": "次要操作標籤",
|
|
11
|
-
"raw": "接受 msg.payload 中的原始 HTML/JS",
|
|
12
|
-
"className": "CSS 類名",
|
|
13
|
-
"topic": "主題",
|
|
14
|
-
"name": "名稱",
|
|
15
|
-
"notificationType": "通知類型",
|
|
16
|
-
"showIcon": "顯示圖標",
|
|
17
|
-
"customIcon": "自定義圖標",
|
|
18
|
-
"showCountdown": "顯示倒計時進度條",
|
|
19
|
-
"playSound": "播放音效",
|
|
20
|
-
"preserveCase": "保留按鈕大小寫(不強制全大寫)",
|
|
21
|
-
"showDialog": "顯示對話框",
|
|
22
|
-
"showNotification": "顯示通知"
|
|
23
|
-
},
|
|
24
|
-
"option": {
|
|
25
|
-
"topRight": "右上角",
|
|
26
|
-
"bottomRight": "右下角",
|
|
27
|
-
"topLeft": "左上角",
|
|
28
|
-
"bottomLeft": "左下角",
|
|
29
|
-
"dialog": "確認 / 取消 對話框",
|
|
30
|
-
"prompt": "帶文本輸入的對話框",
|
|
31
|
-
"default": "默認",
|
|
32
|
-
"info": "ℹ 信息",
|
|
33
|
-
"success": "✓ 成功",
|
|
34
|
-
"warning": "⚠ 警告",
|
|
35
|
-
"error": "✕ 錯誤"
|
|
36
|
-
},
|
|
37
|
-
"placeholder": {
|
|
38
|
-
"timeout": "[msg.timeout]",
|
|
39
|
-
"highlight": "(可選)例如 #ff0000 或 red",
|
|
40
|
-
"ok": "確認按鈕標籤",
|
|
41
|
-
"cancel": "(可選)取消按鈕標籤",
|
|
42
|
-
"className": "[msg.className]",
|
|
43
|
-
"topic": "[msg.topic]",
|
|
44
|
-
"name": "名稱",
|
|
45
|
-
"customIcon": "例如 fa-bell、fa-check"
|
|
46
|
-
},
|
|
47
|
-
"section": {
|
|
48
|
-
"appearance": "外觀設置",
|
|
49
|
-
"behavior": "行為設置",
|
|
50
|
-
"dialog": "對話框設置",
|
|
51
|
-
"advanced": "高級設置"
|
|
52
|
-
},
|
|
53
|
-
"tip": {
|
|
54
|
-
"raw": "<b>警告</b>:啟用 <i>接受原始 HTML/JS</i> 可能導致代碼注入風險,請確保輸入來源可信。",
|
|
55
|
-
"icon": "請使用 Font Awesome 4 圖標類名(例如 fa-bell、fa-check)"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<script type="text/html" data-help-name="ui_notification_better">
|
|
2
|
-
<p>專為 <b>Node-RED Dashboard</b> 量身打造的強化版通知 (Notification / Toast) 與互動式對話框 (Dialog) 節點。</p>
|
|
3
|
-
|
|
4
|
-
<h3>核心特色</h3>
|
|
5
|
-
<ul>
|
|
6
|
-
<li><b>忠實保留按鈕大小寫</b>:徹底解除 Angular Material 強制大寫的限制,輸入「Ok」即顯示「Ok」,大小寫百分之百精確呈現。</li>
|
|
7
|
-
<li><b>通知等級預設</b>:內建 Info(資訊)、Success(成功)、Warning(警告)、Error(錯誤)四種視覺主題與自動圖示。</li>
|
|
8
|
-
<li><b>音效提醒</b>:內建 Web Audio API 音效支援,可發出清脆的提示聲。</li>
|
|
9
|
-
<li><b>豐富的自訂性</b>:支援原生 HTML / JavaScript、倒數進度條、自訂外框顏色與圖示。</li>
|
|
10
|
-
</ul>
|
|
11
|
-
|
|
12
|
-
<h3>輸入屬性 (Inputs)</h3>
|
|
13
|
-
<dl class="message-properties">
|
|
14
|
-
<dt>payload <span class="property-type">字串 | 物件</span></dt>
|
|
15
|
-
<dd>顯示在彈出框中的主要內容。若啟用「允許原始 HTML / JS」,將忠實渲染 HTML 與動畫標籤。</dd>
|
|
16
|
-
|
|
17
|
-
<dt class="optional">topic <span class="property-type">字串</span></dt>
|
|
18
|
-
<dd>通知或對話框的頂部標題。</dd>
|
|
19
|
-
|
|
20
|
-
<dt class="optional">timeout <span class="property-type">數值</span></dt>
|
|
21
|
-
<dd>自動關閉的顯示秒數(預設 3 秒),設為 0 會立即關閉。</dd>
|
|
22
|
-
|
|
23
|
-
<dt class="optional">notificationType <span class="property-type">字串</span></dt>
|
|
24
|
-
<dd>通知等級,可指定為 <code>default</code>、<code>info</code>、<code>success</code>、<code>warning</code> 或 <code>error</code>。</dd>
|
|
25
|
-
|
|
26
|
-
<dt class="optional">ok <span class="property-type">字串</span></dt>
|
|
27
|
-
<dd>確認按鈕文字(完全保留原始大小寫)。</dd>
|
|
28
|
-
|
|
29
|
-
<dt class="optional">cancel <span class="property-type">字串</span></dt>
|
|
30
|
-
<dd>取消按鈕文字(完全保留原始大小寫)。</dd>
|
|
31
|
-
|
|
32
|
-
<dt class="optional">highlight <span class="property-type">字串</span></dt>
|
|
33
|
-
<dd>外框高亮顏色(例如 <code>#2ecc71</code> 或 <code>green</code>)。</dd>
|
|
34
|
-
|
|
35
|
-
<dt class="optional">icon <span class="property-type">字串</span></dt>
|
|
36
|
-
<dd>自訂 Font Awesome 圖示名稱(例如 <code>fa-bell</code>)。</dd>
|
|
37
|
-
|
|
38
|
-
<dt class="optional">playSound <span class="property-type">布林值</span></dt>
|
|
39
|
-
<dd>是否在彈出通知時播放提示音效。</dd>
|
|
40
|
-
|
|
41
|
-
<dt class="optional">socketid <span class="property-type">字串</span></dt>
|
|
42
|
-
<dd>若未勾選廣播至所有工作階段,可指定單一瀏覽器連線的 Session ID。</dd>
|
|
43
|
-
</dl>
|
|
44
|
-
|
|
45
|
-
<h3>輸出屬性 (Outputs)</h3>
|
|
46
|
-
<dl class="message-properties">
|
|
47
|
-
<dt>payload <span class="property-type">字串</span></dt>
|
|
48
|
-
<dd>當佈局設為 <b>Dialog</b>(確認對話框)或 <b>Prompt</b>(文字輸入對話框)時,使用者點擊或輸入確認後的結果將由輸出點發送。</dd>
|
|
49
|
-
</dl>
|
|
50
|
-
</script>
|