aloha-vue 1.2.89 → 1.2.91

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.
@@ -1,7 +1,6 @@
1
1
  {
2
- "_PAGE_FILTER_LIMIT_TO_ARGUMENTS_TEXT_": "Der Eingangsstring, der beschnitten werden soll",
3
- "_PAGE_FILTER_LIMIT_TO_ARGUMENTS_LIMIT_": "Die maximale Länge des zurückgegebenen Strings",
4
- "_PAGE_FILTER_LIMIT_TO_ARGUMENTS_MAX_THREE_DOTS_": "Gibt an, ob maximal drei Punkten am Ende des Strings angezeigt werden",
5
- "_PAGE_FILTER_LIMIT_TO_ARGUMENTS_": "# Argumenti: \ntext (string): Ulazni string čija će duljina biti ograničena\n[limit=30] (cijeli broj): Maksimalna duljina povratnog stringa\n[maxThreeDots=true] (boolean): Određuje hoće li se najviše tri točke vratiti na kraju povratnog stringa\n",
2
+ "_PAGE_FILTER_LIMIT_TO_ARGUMENTS_TEXT_": "Ulazni string čija će duljina biti ograničena.",
3
+ "_PAGE_FILTER_LIMIT_TO_ARGUMENTS_LIMIT_": "Maksimalna duljina povratnog stringa",
4
+ "_PAGE_FILTER_LIMIT_TO_ARGUMENTS_MAX_THREE_DOTS_": "Određuje hoće li se najviše tri točke vratiti na kraju povratnog stringa.",
6
5
  "_PAGE_FILTER_LIMIT_TO_DESCRIPTION_": "Funkcija <strong>filterLimitTo</strong> koristi se za ograničavanje duljine ulaznog stringa na zadanu maksimalnu vrijednost, kao i za opcionalno primjenjivanje posebne logike točaka na kraju stringa."
7
6
  }
@@ -1,14 +1,13 @@
1
1
  {
2
- "_PAGE_FILTER_LIST_ARGUMENTS_ARRAY_": "Das Array für die Liste",
3
- "_PAGE_FILTER_LIST_ARGUMENTS_IS_HTML_": "Wenn true, wird eine HTML-Liste (&lt;ul&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;) erstellt. Andernfalls wird eine Textliste generiert",
4
- "_PAGE_FILTER_LIST_ARGUMENTS_IS_SIMPLE_ARRAY_": "Gibt an, ob nur ein einfaches Array ohne Objekte verwendet wird",
5
- "_PAGE_FILTER_LIST_ARGUMENTS_KEY_CHILDREN_": "Schlüssel für Kinderelemente (nur wenn <strong>isSimpleArray=false</strong>)",
6
- "_PAGE_FILTER_LIST_ARGUMENTS_KEY_LABEL_": "Schlüssel für das anzuzeigende Text (nur wenn <strong>isSimpleArray=false</strong>)",
7
- "_PAGE_FILTER_LIST_ARGUMENTS_KEY_LABEL_CALLBACK_": "Funktion zur Generierung von Labels mit zwei Parametern (<strong>item</strong>, <strong>itemIndex</strong>)",
8
- "_PAGE_FILTER_LIST_ARGUMENTS_SEPARATOR_": "Separator zwischen Elementen (nur wenn <strong>isHtml=false</strong>)",
9
- "_PAGE_FILTER_LIST_ARGUMENTS_TAG_": "HTML-Tag für die gesamte Liste",
10
- "_PAGE_FILTER_LIST_ARGUMENTS_LIST_CLASS_": "CSS-Klasse z.B.: (a_list_without_styles)",
11
- "_PAGE_FILTER_LIST_ARGUMENTS_": "# Argumenti: \narray (niz): Niz od kojeg se kreira lista\n[isHtml=true] (boolean): Za istinitu vrijednost će se kreirati lista u HTML formatu (<ul><li>...</li></ul>). U suprotnom će se kreirati lista u tekstualnom formatu (<span>...</span>)\n[isSimpleArray=false] (boolean): Određuje hoće li se koristiti jednostavan niz bez objekata\n[keyChildren=\"\"] (string): Ključ za podelemente (samo ako je isSimpleArray=false)\n[keyLabel=\"\"] (string): Ključ teksta koji će biti prikazan (samo ako je isSimpleArray=false)\n[keyLabelCallback] (funkcija): Funkcija za generiranje oznaka s dva parametra (item, itemIndex)\n[separator=\", \"] (string): separator između elemenata (samo ako je isHtml=false)\n[tag=\"ul\"] (string): HTML oznaka za cijelu listu\n[listClass=\"\"] (sString): CSS klasa (a_list_without_styles)",
2
+ "_PAGE_FILTER_LIST_ARGUMENTS_ARRAY_": "Niz od kojeg se kreira lista",
3
+ "_PAGE_FILTER_LIST_ARGUMENTS_IS_HTML_": "Za <strong>istinitu</strong> vrijednost će se kreirati lista u HTML formatu (&lt;ul&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;). U suprotnom će se kreirati lista u tekstualnom formatu.",
4
+ "_PAGE_FILTER_LIST_ARGUMENTS_IS_SIMPLE_ARRAY_": "Određuje hoće li se koristiti jednostavan niz bez objekata.",
5
+ "_PAGE_FILTER_LIST_ARGUMENTS_KEY_CHILDREN_": "Ključ za podelemente (samo ako je <strong>isSimpleArray=false</strong>)",
6
+ "_PAGE_FILTER_LIST_ARGUMENTS_KEY_LABEL_": "Ključ teksta koji će biti prikazan (samo ako je <strong>isSimpleArray=false</strong>)",
7
+ "_PAGE_FILTER_LIST_ARGUMENTS_KEY_LABEL_CALLBACK_": "Funkcija za generiranje oznaka s dva parametra (<strong>item</strong>, <strong>itemIndex</strong>).",
8
+ "_PAGE_FILTER_LIST_ARGUMENTS_SEPARATOR_": "Separator separator između elemenata (samo ako je <strong>isHtml=false</strong>)",
9
+ "_PAGE_FILTER_LIST_ARGUMENTS_TAG_": "HTML oznaka za cijelu listu",
10
+ "_PAGE_FILTER_LIST_ARGUMENTS_LIST_CLASS_": "CSS klasa (Npr. a_list_without_styles)",
12
11
  "_PAGE_FILTER_LIST_DESCRIPTION_": "Ova funkcija kreira listu od niza.",
13
12
  "_PAGE_FILTER_LIST_IS_SIMPLE_ARRAY_TREE_HEADER_": "Struktura stabla isSimpleArray=true"
14
13
  }
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "Vue.js"
15
15
  ],
16
16
  "homepage": "https://github.com/ilia-brykin/aloha/#README.md",
17
- "version": "1.2.89",
17
+ "version": "1.2.91",
18
18
  "author": {
19
19
  "name": "Ilia Brykin",
20
20
  "email": "brykin.ilia@gmail.com"
@@ -5,6 +5,7 @@ import {
5
5
  export const selectPluginOptions = ref({
6
6
  propsDefault: {
7
7
  buttonClass: undefined,
8
+ caretIcon: "ChevronDown",
8
9
  countMultiselect: 4,
9
10
  dataExtra: [],
10
11
  inBody: true,
@@ -18,7 +18,7 @@ export const tinymcePluginOptions = ref({
18
18
  maxlength: undefined,
19
19
  menu: undefined,
20
20
  menubar: false,
21
- plugins: "advlist code emoticons link lists table help",
21
+ plugins: "advlist code emoticons link lists table help example",
22
22
  promotion: false,
23
23
  rows: undefined,
24
24
  toolbar: [
@@ -32,7 +32,12 @@ export const tinymcePluginOptions = ref({
32
32
  { name: "Hilfe", items: ["help"] },
33
33
  ],
34
34
  toolbarMode: "wrap",
35
- validElements: "@[style],a[href|target|title],strong/b,em/i,div,br,p,span,ul,ol,li,table,thead,tbody,th,tr,td",
35
+ validElements: "@[style],a[href|target|title],strong/b[style],em/i[style],br[style],p[style],span[style],ul[style],ol[style],li[style],table[],thead[],tbody[],th[],tr[],td[]",
36
+ validStyles: {
37
+ "*": "text-align,padding-left,text-decoration",
38
+ ul: "list-style-type",
39
+ ol: "list-style-type",
40
+ },
36
41
  },
37
42
  });
38
43
 
@@ -11,6 +11,8 @@
11
11
  .a_select_toggle {
12
12
  position: relative;
13
13
  min-width: var(--a_select_min_width);
14
+ min-height: calc(26px + 0.375rem * 2);
15
+ padding-right: 30px;
14
16
  text-align: left;
15
17
  }
16
18
  .a_select_toggle_closeable {
@@ -18,12 +20,14 @@
18
20
  }
19
21
 
20
22
  .a_caret {
21
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
22
- background-repeat: no-repeat;
23
- background-position: right 0.75rem center;
24
- background-size: 16px 12px;
25
- min-height: calc(26px + 0.375rem * 2);
26
- padding-right: 26px;
23
+ display: flex;
24
+ align-items: center;
25
+ justify-content: center;
26
+ position: absolute;
27
+ right: 0;
28
+ top: 0;
29
+ height: 100%;
30
+ width: 30px;
27
31
  }
28
32
 
29
33
  .a_select__search {
@@ -161,6 +165,7 @@
161
165
  overflow-x: hidden;
162
166
  text-overflow: ellipsis;
163
167
  white-space: nowrap;
168
+ padding-right: 18px;
164
169
  }
165
170
 
166
171
  .a_select__ul_closeable {
@@ -56,6 +56,11 @@ export default {
56
56
  required: false,
57
57
  default: () => selectPluginOptions.value.propsDefault.buttonClass,
58
58
  },
59
+ caretIcon: {
60
+ type: [String, Object],
61
+ required: false,
62
+ default: () => selectPluginOptions.value.propsDefault.caretIcon,
63
+ },
59
64
  change: {
60
65
  type: Function,
61
66
  required: false,
@@ -614,7 +619,7 @@ export default {
614
619
  h("div", {
615
620
  ref: "buttonRef",
616
621
  id: this.htmlIdLocal,
617
- class: ["a_form_control a_select_toggle a_caret", this.buttonClass, {
622
+ class: ["a_form_control a_select_toggle", this.buttonClass, {
618
623
  disabled: this.disabled,
619
624
  a_select_toggle_closeable: this.isMultiselect && this.isSelectionCloseable,
620
625
  a_form_control_invalid: this.isErrors,
@@ -853,6 +858,13 @@ export default {
853
858
  ]),
854
859
  ]),
855
860
  ]),
861
+ h("span", {
862
+ class: "a_caret",
863
+ }, [
864
+ h(AIcon, {
865
+ icon: this.caretIcon,
866
+ }),
867
+ ])
856
868
  ]),
857
869
  ]),
858
870
  ]),
@@ -96,6 +96,11 @@ export default {
96
96
  required: false,
97
97
  default: () => tinymcePluginOptions.value.propsDefault.validElements,
98
98
  },
99
+ validStyles: {
100
+ type: Object,
101
+ required: false,
102
+ default: () => tinymcePluginOptions.value.propsDefault.validStyles,
103
+ },
99
104
  },
100
105
  setup(props, context) {
101
106
  const {
@@ -5,8 +5,11 @@ import {
5
5
  watch,
6
6
  } from "vue";
7
7
 
8
+ import MyPowerPaste from "../plugins/MyPowerPaste";
9
+
8
10
  /* Import TinyMCE */
9
11
  import tinymce from "tinymce";
12
+ tinymce.PluginManager.add("example", MyPowerPaste);
10
13
 
11
14
  /* Default icons are required. After that, import custom icons if applicable */
12
15
  import "tinymce/icons/default";
@@ -57,6 +60,7 @@ export default function ATinymceAPI(props, context, {
57
60
  const toolbar = toRef(props, "toolbar");
58
61
  const toolbarMode = toRef(props, "toolbarMode");
59
62
  const validElements = toRef(props, "validElements");
63
+ const validStyles = toRef(props, "validStyles");
60
64
 
61
65
  let vueEditor = null;
62
66
  let modelValueLocal = undefined;
@@ -89,6 +93,8 @@ export default function ATinymceAPI(props, context, {
89
93
  menubar: menubar.value,
90
94
  readonly: !!disabled.value,
91
95
  valid_elements: validElements.value,
96
+ valid_styles: validStyles.value,
97
+
92
98
  setup: editor => {
93
99
  vueEditor = editor;
94
100
  editor.on("change input undo redo", () => {
@@ -0,0 +1,187 @@
1
+ import {
2
+ forEach,
3
+ } from "lodash-es";
4
+
5
+ export default function(editor) {
6
+ // Event-Handler für Einfügevorgänge
7
+ editor.on("paste", function(e) {
8
+ const clipboardData = (e.clipboardData || window.clipboardData);
9
+ e.stopPropagation();
10
+ e.preventDefault();
11
+
12
+ const PAGE_HTML = clipboardData.getData("text/html");
13
+ const HTML_FRAGMENT = extractTextBetween({
14
+ html: PAGE_HTML,
15
+ start: "<!--StartFragment-->",
16
+ end: "<!--EndFragment-->",
17
+ });
18
+
19
+ if (isMsWord({ html: PAGE_HTML })) {
20
+ editor.insertContent(parseWord({ html: HTML_FRAGMENT }));
21
+ } else {
22
+ const cleanedHtml = HTML_FRAGMENT.replace(/\sdata-[a-z0-9-]+="[^"]*"/gi, "").replace(/\saria-[a-z0-9-]+="[^"]*"/gi, "");
23
+
24
+ editor.insertContent(cleanedHtml);
25
+ }
26
+ });
27
+ /* Return the metadata for the help plugin */
28
+ return {
29
+ getMetadata: () => ({
30
+ name: "My power paste",
31
+ url: "https://ilia-brykin.github.io/aloha/#/"
32
+ })
33
+ };
34
+ }
35
+
36
+ function extractTextBetween({ html, start, end }) {
37
+ const startIndex = html.indexOf(start);
38
+ const endIndex = html.indexOf(end);
39
+
40
+ if (startIndex !== -1 && endIndex !== -1) {
41
+ return html.substring(startIndex + start.length, endIndex).trim();
42
+ }
43
+ return html;
44
+ }
45
+
46
+ function isMsWord({ html }) {
47
+ const HTML_TAG = extractTextBetween({
48
+ html,
49
+ start: "<html",
50
+ end: ">",
51
+ });
52
+
53
+ return HTML_TAG.indexOf(":office:word") !== -1;
54
+ }
55
+
56
+ function parseWord({ html }) {
57
+ const parser = new DOMParser();
58
+ const doc = parser.parseFromString(html, "text/html");
59
+ const allChildren = doc.body.querySelectorAll(":scope > *");
60
+
61
+ const rootElement = document.createElement("div");
62
+ let currentList = null;
63
+ let lastLevel = 0;
64
+ const listStack = [];
65
+
66
+ forEach(allChildren, element => {
67
+ const isTagP = element.tagName === "P";
68
+ if (!isTagP) {
69
+ rootElement.appendChild(element);
70
+ lastLevel = 0;
71
+ currentList = null;
72
+ return;
73
+ }
74
+
75
+ const isNormalParagraph = element.className.includes("MsoNormal");
76
+ const htmlContent = element.innerHTML.trim()
77
+ .replace(/<u>/g, "<span style=\"text-decoration: underline;\">")
78
+ .replace(/<\/u>/g, "</span>")
79
+ .replace(/<!--\[if !supportLists]-->.*?<!--\[endif]-->/gs, "")
80
+ .replace(/&nbsp;/g, " ")
81
+ .replace(/^[\s·o§1-9]+[.)]?/g, "");
82
+
83
+ if (isTagP && isNormalParagraph && !element.className.includes("MsoListParagraph")) {
84
+ const newParagraph = document.createElement("p");
85
+ newParagraph.innerHTML = htmlContent;
86
+ rootElement.appendChild(newParagraph);
87
+ lastLevel = 0;
88
+ currentList = null;
89
+ return;
90
+ }
91
+
92
+ const LIST_LEVEL = getCurrentLevelForList(element);
93
+ const { type, style } = getListTypeAndStyleFromSpanContent(element);
94
+
95
+ if (!currentList || LIST_LEVEL > lastLevel) {
96
+ const newList = document.createElement(type);
97
+ if (style) {
98
+ newList.style.listStyleType = style;
99
+ }
100
+
101
+ if (currentList) {
102
+ currentList.appendChild(newList);
103
+ } else {
104
+ rootElement.appendChild(newList);
105
+ }
106
+ currentList = newList;
107
+ listStack.push({ element: newList, level: LIST_LEVEL });
108
+ } else if (LIST_LEVEL < lastLevel) {
109
+ while (listStack.length > 1 && LIST_LEVEL < listStack[listStack.length - 1].level) {
110
+ listStack.pop();
111
+ currentList = listStack[listStack.length - 1].element;
112
+ }
113
+ }
114
+
115
+ const li = document.createElement("li");
116
+ li.innerHTML = htmlContent;
117
+ currentList.appendChild(li);
118
+
119
+ lastLevel = LIST_LEVEL;
120
+ });
121
+
122
+ return rootElement.innerHTML;
123
+ }
124
+
125
+ function getListTypeAndStyleFromSpanContent(p) {
126
+ const spans = p.querySelectorAll("span");
127
+ let spanContent = "";
128
+ forEach(spans, span => {
129
+ const styleAttr = span.getAttribute("style");
130
+ if (styleAttr && styleAttr.includes("mso-list:Ignore")) {
131
+ spanContent = span.textContent || "";
132
+ return false;
133
+ }
134
+ });
135
+
136
+ spanContent = spanContent.trim();
137
+ if (!spanContent) {
138
+ return { type: "ul", style: "" };
139
+ }
140
+ // Check for ordered list with Arabic numerals or numbers within parentheses
141
+ if (/^\d+[.)]/.test(spanContent) || /^\(\d+\)/.test(spanContent)) {
142
+ return { type: "ol", style: "" }; // Default style for <ol>
143
+ }
144
+ // Check for ordered list with uppercase Roman numerals
145
+ if (/^[IVXLCDM]+\./.test(spanContent)) {
146
+ return { type: "ol", style: "upper-roman" };
147
+ }
148
+ // Check for ordered list with lowercase Roman numerals
149
+ if (/^[ivxlcdm]+\./.test(spanContent)) {
150
+ return { type: "ol", style: "lower-roman" };
151
+ }
152
+ // Check for ordered list with uppercase letters
153
+ if (/^[A-Z]+[.)]/.test(spanContent)) {
154
+ return { type: "ol", style: "upper-alpha" };
155
+ }
156
+ // Check for ordered list with lowercase letters
157
+ if (/^[a-z]+[.)]/.test(spanContent)) {
158
+ return { type: "ol", style: "lower-alpha" };
159
+ }
160
+ // Check for unordered list with various symbols
161
+ if (/^[·o§]/.test(spanContent)) {
162
+ // Determine list style based on the symbol
163
+ let style;
164
+ switch (spanContent.trim()[0]) {
165
+ case "·": style = "disc"; break;
166
+ case "o": style = "circle"; break;
167
+ case "§": style = "square"; break;
168
+ default: style = "";
169
+ }
170
+ return { type: "ul", style: style };
171
+ }
172
+
173
+ return { type: "ul", style: "" };
174
+ }
175
+
176
+ function getCurrentLevelForList(p) {
177
+ const styleAttr = p.getAttribute("style");
178
+ let level = 1;
179
+ if (styleAttr) {
180
+ const levelMatch = styleAttr.match(/mso-list:l\d+ level(\d+)/);
181
+ if (levelMatch) {
182
+ level = parseInt(levelMatch[1], 10);
183
+ }
184
+ }
185
+
186
+ return level;
187
+ }