formstrap 0.4.9 → 0.4.11
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/formstrap/controllers/media_controller.js +8 -4
- data/app/assets/javascripts/formstrap/vendor/redactor/i18n/nl.js +1 -1
- data/app/assets/javascripts/formstrap/vendor/redactor/plugins/ai.js +958 -982
- data/app/assets/javascripts/formstrap/vendor/redactor/plugins/linkstyles.js +2 -2
- data/app/assets/javascripts/formstrap.js +105 -98
- data/app/models/concerns/formstrap/labelable.rb +2 -1
- data/app/views/formstrap/_association.html.erb +1 -0
- data/app/views/formstrap/_checkbox.html.erb +1 -0
- data/app/views/formstrap/_color.html.erb +1 -0
- data/app/views/formstrap/_date.html.erb +1 -0
- data/app/views/formstrap/_email.html.erb +1 -0
- data/app/views/formstrap/_file.html.erb +1 -0
- data/app/views/formstrap/_label.html.erb +5 -0
- data/app/views/formstrap/_media.html.erb +2 -1
- data/app/views/formstrap/_number.html.erb +1 -0
- data/app/views/formstrap/_password.html.erb +1 -0
- data/app/views/formstrap/_redactor.html.erb +1 -0
- data/app/views/formstrap/_select.html.erb +1 -0
- data/app/views/formstrap/_switch.html.erb +2 -1
- data/app/views/formstrap/_text.html.erb +2 -1
- data/app/views/formstrap/_textarea.html.erb +1 -0
- data/app/views/formstrap/_wysiwyg.html.erb +1 -0
- data/config/locales/formstrap/de.yml +2 -0
- data/config/locales/formstrap/en.yml +2 -0
- data/config/locales/formstrap/fr.yml +2 -0
- data/config/locales/formstrap/nl.yml +2 -0
- data/lib/formstrap/version.rb +1 -1
- data/package.json +1 -1
- metadata +2 -3
- data/app/views/formstrap/shared/_notifications.html.erb +0 -20
@@ -31,12 +31,12 @@ Redactor.add('plugin', 'linkstyles', {
|
|
31
31
|
}
|
32
32
|
},
|
33
33
|
'link.change': function (e) {
|
34
|
-
let link = e.
|
34
|
+
let link = e.data.element.nodes[0]
|
35
35
|
link = this.ensureValidProtocol(link)
|
36
36
|
this.applyStylingToLink(link)
|
37
37
|
},
|
38
38
|
'link.add': function (e) {
|
39
|
-
let link = e.
|
39
|
+
let link = e.data.element.nodes[0]
|
40
40
|
link = this.ensureValidProtocol(link)
|
41
41
|
this.applyStylingToLink(link)
|
42
42
|
}
|
@@ -11204,10 +11204,11 @@ var media_controller_default = class extends Controller {
|
|
11204
11204
|
}
|
11205
11205
|
}
|
11206
11206
|
togglePlaceholder() {
|
11207
|
-
|
11208
|
-
|
11209
|
-
} else {
|
11207
|
+
const count = this.activeItems().length;
|
11208
|
+
if (count < this.maxActiveItems()) {
|
11210
11209
|
this.showPlaceholder();
|
11210
|
+
} else {
|
11211
|
+
this.hidePlaceholder();
|
11211
11212
|
}
|
11212
11213
|
}
|
11213
11214
|
showPlaceholder() {
|
@@ -11223,7 +11224,7 @@ var media_controller_default = class extends Controller {
|
|
11223
11224
|
createItem(item) {
|
11224
11225
|
let templateHtml = this.templateTarget;
|
11225
11226
|
templateHtml = this.randomizeIds(templateHtml);
|
11226
|
-
this.thumbnailsTarget.insertAdjacentHTML("
|
11227
|
+
this.thumbnailsTarget.children[this.thumbnailsTarget.children.length - 1].insertAdjacentHTML("beforebegin", templateHtml);
|
11227
11228
|
const newItem = this.itemTargets.pop();
|
11228
11229
|
newItem.querySelector('input[name*="[blob_id]"]').value = item.blobId;
|
11229
11230
|
newItem.querySelector('input[name*="[_destroy]"]').value = false;
|
@@ -14603,12 +14604,12 @@ Redactor.add("plugin", "linkstyles", {
|
|
14603
14604
|
}
|
14604
14605
|
},
|
14605
14606
|
"link.change": function(e) {
|
14606
|
-
let link = e.
|
14607
|
+
let link = e.data.element.nodes[0];
|
14607
14608
|
link = this.ensureValidProtocol(link);
|
14608
14609
|
this.applyStylingToLink(link);
|
14609
14610
|
},
|
14610
14611
|
"link.add": function(e) {
|
14611
|
-
let link = e.
|
14612
|
+
let link = e.data.element.nodes[0];
|
14612
14613
|
link = this.ensureValidProtocol(link);
|
14613
14614
|
this.applyStylingToLink(link);
|
14614
14615
|
}
|
@@ -14683,14 +14684,14 @@ Redactor.add("plugin", "linkstyles", {
|
|
14683
14684
|
Redactor.add("plugin", "ai", {
|
14684
14685
|
translations: {
|
14685
14686
|
en: {
|
14686
|
-
|
14687
|
+
ai: {
|
14687
14688
|
"placeholder-image": "Describe the image you want to generate.",
|
14688
14689
|
"placeholder-text": "Tell me what you want to write.",
|
14689
|
-
|
14690
|
-
|
14691
|
-
|
14692
|
-
|
14693
|
-
|
14690
|
+
send: "Send",
|
14691
|
+
stop: "Stop",
|
14692
|
+
discard: "Discard",
|
14693
|
+
insert: "Insert",
|
14694
|
+
prompt: "Prompt",
|
14694
14695
|
"image-style": "Image style",
|
14695
14696
|
"change-tone": "Change tone"
|
14696
14697
|
}
|
@@ -14771,7 +14772,7 @@ Redactor.add("plugin", "ai", {
|
|
14771
14772
|
return obj;
|
14772
14773
|
},
|
14773
14774
|
popup(e, button) {
|
14774
|
-
|
14775
|
+
const uiState = this.app.ui.getState();
|
14775
14776
|
if (uiState.type !== "addbar") {
|
14776
14777
|
this.app.dropdown.create("ai-tools", { items: this.opts.get("ai.items") || this.dropdowns.items });
|
14777
14778
|
this.app.dropdown.open(e, button);
|
@@ -14783,8 +14784,8 @@ Redactor.add("plugin", "ai", {
|
|
14783
14784
|
this._buildPrompt({ image: true });
|
14784
14785
|
},
|
14785
14786
|
popupTone(e, button) {
|
14786
|
-
|
14787
|
-
|
14787
|
+
const buttons = {};
|
14788
|
+
const items = this.opts.get("ai.tone") || this.defaults.tone;
|
14788
14789
|
const makeit = this.opts.get("ai.makeit") || this.defaults.makeit;
|
14789
14790
|
for (let i = 0; i < items.length; i++) {
|
14790
14791
|
buttons[i] = { title: items[i], command: "ai.set", params: { prompt: makeit + " " + items[i] } };
|
@@ -14793,8 +14794,8 @@ Redactor.add("plugin", "ai", {
|
|
14793
14794
|
this.app.dropdown.open(e, button);
|
14794
14795
|
},
|
14795
14796
|
popupTranslate(e, button) {
|
14796
|
-
|
14797
|
-
|
14797
|
+
const buttons = {};
|
14798
|
+
const items = this.opts.get("ai.translate") || this.defaults.translate;
|
14798
14799
|
const translateto = this.opts.get("ai.translateto") || this.defaults.translateto;
|
14799
14800
|
for (let i = 0; i < items.length; i++) {
|
14800
14801
|
buttons[i] = { title: items[i], command: "ai.set", params: { prompt: translateto + " " + items[i] } };
|
@@ -14815,7 +14816,7 @@ Redactor.add("plugin", "ai", {
|
|
14815
14816
|
this.promptButton.setIcon(this.defaults.spinner);
|
14816
14817
|
}
|
14817
14818
|
let message = params.prompt;
|
14818
|
-
|
14819
|
+
const event = this.app.broadcast("ai.create", { prompt: message });
|
14819
14820
|
message = event.get("prompt");
|
14820
14821
|
this.modifiedValue = message;
|
14821
14822
|
this._setPrompt(text, html, message, params.empty);
|
@@ -14823,18 +14824,18 @@ Redactor.add("plugin", "ai", {
|
|
14823
14824
|
sendPrompt(e) {
|
14824
14825
|
e.preventDefault();
|
14825
14826
|
e.stopPropagation();
|
14826
|
-
|
14827
|
+
const apimodel = this.opts.get("ai." + this.promptType + ".model");
|
14827
14828
|
let message = this._getMessage();
|
14828
|
-
|
14829
|
+
const event = this.app.broadcast("ai.create", { prompt: message });
|
14829
14830
|
message = event.get("prompt");
|
14830
14831
|
this.modifiedValue = message;
|
14831
14832
|
if (message === "")
|
14832
14833
|
return;
|
14833
|
-
|
14834
|
+
const tone = this._getTone(message);
|
14834
14835
|
if (this.promptType === "text") {
|
14835
|
-
this.conversation.push({
|
14836
|
+
this.conversation.push({ role: "user", content: message });
|
14836
14837
|
if (tone) {
|
14837
|
-
this.conversation.push({
|
14838
|
+
this.conversation.push({ role: "user", content: tone });
|
14838
14839
|
}
|
14839
14840
|
}
|
14840
14841
|
let request = {
|
@@ -14857,20 +14858,20 @@ Redactor.add("plugin", "ai", {
|
|
14857
14858
|
insertPrompt(e) {
|
14858
14859
|
e.preventDefault();
|
14859
14860
|
e.stopPropagation();
|
14860
|
-
|
14861
|
+
const insertion = this.app.create("insertion");
|
14861
14862
|
let html = this.$preview.html();
|
14862
14863
|
if (this.promptType === "image") {
|
14863
14864
|
const tag = this.opts.get("image.tag");
|
14864
14865
|
html = `<${tag}>${html}</${tag}>`;
|
14865
14866
|
}
|
14866
|
-
|
14867
|
+
const event = this.app.broadcast("ai.before.insert", { html });
|
14867
14868
|
html = event.get("html");
|
14868
|
-
|
14869
|
-
|
14870
|
-
|
14869
|
+
const $target = this.savedInstance ? this.savedInstance.getBlock() : this.$prompt;
|
14870
|
+
const position = this.savedInstance ? "after" : "before";
|
14871
|
+
const remove = !this.savedInstance;
|
14871
14872
|
setTimeout(function() {
|
14872
14873
|
this.app.block.setTool(false);
|
14873
|
-
|
14874
|
+
const inserted = insertion.insert({ html, target: $target, position, remove });
|
14874
14875
|
this.$prompt.remove();
|
14875
14876
|
this.conversation = [];
|
14876
14877
|
this.app.broadcast("ai.insert", { nodes: inserted });
|
@@ -14890,9 +14891,9 @@ Redactor.add("plugin", "ai", {
|
|
14890
14891
|
this.$insert.show();
|
14891
14892
|
this.$stop.hide();
|
14892
14893
|
this.$generate.show();
|
14893
|
-
|
14894
|
-
|
14895
|
-
|
14894
|
+
const eventName = e ? "ai.stop" : "ai.complete";
|
14895
|
+
const prompt = this.$previewLabel.text();
|
14896
|
+
const result = e ? { prompt } : { prompt, response: this._parseReply(reply) };
|
14896
14897
|
this.app.broadcast(eventName, result);
|
14897
14898
|
},
|
14898
14899
|
closePrompt(e) {
|
@@ -14907,7 +14908,7 @@ Redactor.add("plugin", "ai", {
|
|
14907
14908
|
this.app.broadcast("ai.discard");
|
14908
14909
|
},
|
14909
14910
|
_getTone(message) {
|
14910
|
-
|
14911
|
+
const tone = this.$select.val();
|
14911
14912
|
if (tone === "0" || tone === "1") {
|
14912
14913
|
return false;
|
14913
14914
|
}
|
@@ -14916,7 +14917,7 @@ Redactor.add("plugin", "ai", {
|
|
14916
14917
|
_getHtml() {
|
14917
14918
|
let html = "";
|
14918
14919
|
let instances = this.app.blocks.get({ selected: true, instances: true });
|
14919
|
-
|
14920
|
+
const instance = this.app.block.get();
|
14920
14921
|
if (instances.length === 0 && instance) {
|
14921
14922
|
instances = [instance];
|
14922
14923
|
}
|
@@ -14928,13 +14929,14 @@ Redactor.add("plugin", "ai", {
|
|
14928
14929
|
_getText() {
|
14929
14930
|
let text = "";
|
14930
14931
|
let instances = this.app.blocks.get({ selected: true, instances: true });
|
14931
|
-
|
14932
|
+
const instance = this.app.block.get();
|
14932
14933
|
if (instances.length === 0 && instance) {
|
14933
14934
|
instances = [instance];
|
14934
14935
|
}
|
14935
14936
|
for (let i = 0; i < instances.length; i++) {
|
14936
14937
|
if (instances[i].isEditable()) {
|
14937
|
-
|
14938
|
+
const type = instances[i].getType();
|
14939
|
+
const prefix = type === "listitem" ? "- " : "";
|
14938
14940
|
text = text + prefix + instances[i].getPlainText() + "\n";
|
14939
14941
|
}
|
14940
14942
|
}
|
@@ -14946,7 +14948,7 @@ Redactor.add("plugin", "ai", {
|
|
14946
14948
|
return this.$textarea.val().trim();
|
14947
14949
|
},
|
14948
14950
|
_getNode() {
|
14949
|
-
|
14951
|
+
const node = this.app.block.create();
|
14950
14952
|
let $node = node.getBlock();
|
14951
14953
|
$node = this._buildNode($node, { traverse: true });
|
14952
14954
|
return $node;
|
@@ -14963,13 +14965,13 @@ Redactor.add("plugin", "ai", {
|
|
14963
14965
|
this.promptType = "text";
|
14964
14966
|
this.promptText = text;
|
14965
14967
|
this.promptHtml = html;
|
14966
|
-
|
14967
|
-
|
14968
|
+
const messages = [{ role: "user", content: text }, { role: "user", content: prompt }];
|
14969
|
+
const request = {
|
14968
14970
|
model: this.opts.get("ai." + this.promptType + ".model"),
|
14969
14971
|
messages
|
14970
14972
|
};
|
14971
14973
|
if (this.opts.is("ai.text.stream")) {
|
14972
|
-
|
14974
|
+
const $node = this._getInsertedNode();
|
14973
14975
|
$node.html(this.defaults.spinner);
|
14974
14976
|
this.app.dropdown.close();
|
14975
14977
|
this.app.context.close();
|
@@ -14989,7 +14991,7 @@ Redactor.add("plugin", "ai", {
|
|
14989
14991
|
url: this.opts.get("ai." + this.promptType + ".url"),
|
14990
14992
|
data,
|
14991
14993
|
before: function(xhr) {
|
14992
|
-
|
14994
|
+
const event = this.app.broadcast("ai.before.send", { xhr, data });
|
14993
14995
|
if (event.isStopped()) {
|
14994
14996
|
return false;
|
14995
14997
|
}
|
@@ -15002,7 +15004,7 @@ Redactor.add("plugin", "ai", {
|
|
15002
15004
|
const apimodel = this.opts.get("ai." + this.promptType + ".model");
|
15003
15005
|
const apiurl = this.opts.get("ai." + this.promptType + ".endpoint");
|
15004
15006
|
const serverurl = this.opts.get("ai." + this.promptType + ".url");
|
15005
|
-
|
15007
|
+
const request = {
|
15006
15008
|
model: apimodel,
|
15007
15009
|
stream: this.opts.get("ai.text.stream"),
|
15008
15010
|
messages: preview ? this.conversation : message
|
@@ -15014,15 +15016,17 @@ Redactor.add("plugin", "ai", {
|
|
15014
15016
|
const utils = this.app.create("utils");
|
15015
15017
|
data = utils.extendData(data, this.opts.get("ai." + this.promptType + ".data"));
|
15016
15018
|
let responseContent = "";
|
15017
|
-
|
15019
|
+
const source = this._createSource(serverurl, data);
|
15018
15020
|
this.isEvent = source;
|
15019
15021
|
this.currentIndex = 0;
|
15020
|
-
|
15022
|
+
const $target = this.app.scroll.getTarget();
|
15021
15023
|
$node.removeClass("rx-inserted-node-started");
|
15022
15024
|
source.addEventListener("message", function(event) {
|
15023
15025
|
this.app.dropdown.close();
|
15024
15026
|
this.app.context.close();
|
15025
|
-
|
15027
|
+
const message2 = event.data;
|
15028
|
+
const start2 = message2.indexOf(": ", "data") + 2;
|
15029
|
+
let data2 = message2.slice(start2, message2.length);
|
15026
15030
|
if (data2 === "[DONE]") {
|
15027
15031
|
this._sendStreamDone(source, $node, responseContent, preview);
|
15028
15032
|
} else {
|
@@ -15033,7 +15037,7 @@ Redactor.add("plugin", "ai", {
|
|
15033
15037
|
}
|
15034
15038
|
const choices = data2.choices;
|
15035
15039
|
if (choices && choices.length > 0) {
|
15036
|
-
|
15040
|
+
const content = choices[0].delta.content;
|
15037
15041
|
if (content) {
|
15038
15042
|
if (!$node.hasClass("rx-inserted-node-started")) {
|
15039
15043
|
$node.html("");
|
@@ -15060,11 +15064,11 @@ Redactor.add("plugin", "ai", {
|
|
15060
15064
|
if (!preview) {
|
15061
15065
|
this._insertAfterNode($node, responseContent);
|
15062
15066
|
} else {
|
15063
|
-
|
15067
|
+
const checkInterval = setInterval(function() {
|
15064
15068
|
if (this.currentIndex === responseContent.length) {
|
15065
15069
|
clearInterval(checkInterval);
|
15066
15070
|
this.stopPrompt(false, responseContent);
|
15067
|
-
this.conversation.push({
|
15071
|
+
this.conversation.push({ role: "assistant", content: responseContent });
|
15068
15072
|
}
|
15069
15073
|
}.bind(this), 100);
|
15070
15074
|
}
|
@@ -15074,7 +15078,7 @@ Redactor.add("plugin", "ai", {
|
|
15074
15078
|
_sendStreamPreviewSet(preview) {
|
15075
15079
|
if (!preview)
|
15076
15080
|
return;
|
15077
|
-
|
15081
|
+
const value = this.modifiedValue || this.$textarea.val();
|
15078
15082
|
this.$progress.html("");
|
15079
15083
|
this.$previewLabel.html(this._sanitize(value));
|
15080
15084
|
this.$textarea.val("");
|
@@ -15092,7 +15096,7 @@ Redactor.add("plugin", "ai", {
|
|
15092
15096
|
$last = $last.closest("[data-rx-first-level]");
|
15093
15097
|
$last.before($node);
|
15094
15098
|
}
|
15095
|
-
|
15099
|
+
const isAll = this.app.editor.isSelectAll();
|
15096
15100
|
$last = this.app.blocks.removeAll();
|
15097
15101
|
if (isAll) {
|
15098
15102
|
$node = $last;
|
@@ -15101,7 +15105,7 @@ Redactor.add("plugin", "ai", {
|
|
15101
15105
|
this.instance = this.app.block.get();
|
15102
15106
|
if (!this.instance) {
|
15103
15107
|
this.instance = this.app.block.create();
|
15104
|
-
|
15108
|
+
const $first = this.app.blocks.get({ first: true });
|
15105
15109
|
$first.before(this.instance.getBlock());
|
15106
15110
|
}
|
15107
15111
|
if (this.instance.isType("listitem")) {
|
@@ -15123,7 +15127,7 @@ Redactor.add("plugin", "ai", {
|
|
15123
15127
|
this.app.block.setTool("ai");
|
15124
15128
|
}.bind(this));
|
15125
15129
|
let instance = this.app.block.get();
|
15126
|
-
|
15130
|
+
const isMultiple = this.app.blocks.is();
|
15127
15131
|
this.app.dropdown.close();
|
15128
15132
|
this.app.context.close();
|
15129
15133
|
if (instance || isMultiple) {
|
@@ -15131,8 +15135,8 @@ Redactor.add("plugin", "ai", {
|
|
15131
15135
|
instance = this.app.blocks.get({ last: true, selected: true, instances: true });
|
15132
15136
|
}
|
15133
15137
|
const types = ["layout", "table", "quote", "list", "todo", "image", "embed"];
|
15134
|
-
|
15135
|
-
|
15138
|
+
const $parent = instance.getBlock().closest("[data-rx-type=" + types.join("],[data-rx-type=") + "]");
|
15139
|
+
const $column = instance.getBlock().closest("[data-rx-type=column]");
|
15136
15140
|
if ($parent.length !== 0) {
|
15137
15141
|
if ($column.length !== 0) {
|
15138
15142
|
this.savedInstance = instance;
|
@@ -15149,11 +15153,11 @@ Redactor.add("plugin", "ai", {
|
|
15149
15153
|
this.app.editor.adjustHeight();
|
15150
15154
|
},
|
15151
15155
|
_error(error2, response) {
|
15152
|
-
|
15156
|
+
const $node = this.app.editor.getEditor().find(".rx-inserted-node");
|
15153
15157
|
if ($node.length !== 0) {
|
15154
15158
|
this.app.dropdown.close();
|
15155
15159
|
this.app.context.close();
|
15156
|
-
|
15160
|
+
const insertion = this.app.create("insertion");
|
15157
15161
|
insertion.insert({ target: $node, remove: true, caret: "end", html: this.promptHtml });
|
15158
15162
|
}
|
15159
15163
|
if (this.$progress) {
|
@@ -15161,7 +15165,7 @@ Redactor.add("plugin", "ai", {
|
|
15161
15165
|
this.$progress.html("").removeAttr("style");
|
15162
15166
|
}.bind(this));
|
15163
15167
|
}
|
15164
|
-
this.app.broadcast("ai.error", error2
|
15168
|
+
this.app.broadcast("ai.error", error2 || response);
|
15165
15169
|
},
|
15166
15170
|
_insert(response) {
|
15167
15171
|
this.promptButton.setIcon("");
|
@@ -15169,20 +15173,20 @@ Redactor.add("plugin", "ai", {
|
|
15169
15173
|
return this._error(response.error.message, response);
|
15170
15174
|
if (!response.choices)
|
15171
15175
|
return this._error(response);
|
15172
|
-
|
15176
|
+
const reply = response.choices[0].message.content;
|
15173
15177
|
let html = this._parseReply(reply);
|
15174
|
-
|
15175
|
-
|
15178
|
+
const insertion = this.app.create("insertion");
|
15179
|
+
const event = this.app.broadcast("ai.before.insert", { html });
|
15176
15180
|
html = event.get("html");
|
15177
15181
|
this.app.dropdown.close();
|
15178
15182
|
this.app.context.close();
|
15179
15183
|
let inserted;
|
15180
|
-
|
15184
|
+
const instanceType = this.instance && this.instance.isType(["listitem", "todoitem"]);
|
15181
15185
|
if (instanceType) {
|
15182
15186
|
this.instance.setContent(reply);
|
15183
15187
|
inserted = this.instance.getBlock();
|
15184
15188
|
} else {
|
15185
|
-
|
15189
|
+
const $node = this._getNode();
|
15186
15190
|
this.app.block.set($node);
|
15187
15191
|
inserted = insertion.insert({ html, caret: "end" });
|
15188
15192
|
}
|
@@ -15192,7 +15196,7 @@ Redactor.add("plugin", "ai", {
|
|
15192
15196
|
let reply;
|
15193
15197
|
let html;
|
15194
15198
|
let imageUrl;
|
15195
|
-
|
15199
|
+
const value = this.modifiedValue || this.$textarea.val();
|
15196
15200
|
let result;
|
15197
15201
|
this.$progress.html("");
|
15198
15202
|
this.$previewLabel.html("");
|
@@ -15214,7 +15218,7 @@ Redactor.add("plugin", "ai", {
|
|
15214
15218
|
result = html;
|
15215
15219
|
this.$preview.html(html);
|
15216
15220
|
this.$insert.show();
|
15217
|
-
|
15221
|
+
const prompt = this.$previewLabel.text();
|
15218
15222
|
this.app.broadcast("ai.complete", { prompt, response: result });
|
15219
15223
|
this.app.editor.adjustHeight();
|
15220
15224
|
} else if (this.promptType === "image") {
|
@@ -15232,7 +15236,7 @@ Redactor.add("plugin", "ai", {
|
|
15232
15236
|
url: saveUrl,
|
15233
15237
|
data,
|
15234
15238
|
before: function(xhr) {
|
15235
|
-
|
15239
|
+
const event = this.app.broadcast("ai.before.save", { xhr, data });
|
15236
15240
|
if (event.isStopped()) {
|
15237
15241
|
return false;
|
15238
15242
|
}
|
@@ -15249,17 +15253,17 @@ Redactor.add("plugin", "ai", {
|
|
15249
15253
|
}
|
15250
15254
|
},
|
15251
15255
|
_completeImage(imageUrl) {
|
15252
|
-
|
15253
|
-
|
15256
|
+
const $image = this.dom("<img>").attr("src", imageUrl);
|
15257
|
+
const result = $image.get().outerHTML;
|
15254
15258
|
this.$preview.html($image);
|
15255
15259
|
this.$insert.show();
|
15256
|
-
|
15260
|
+
const prompt = this.$previewLabel.text();
|
15257
15261
|
this.app.broadcast("ai.complete", { prompt, response: result });
|
15258
15262
|
this.app.editor.adjustHeight();
|
15259
15263
|
},
|
15260
15264
|
_parseReply(reply) {
|
15261
|
-
|
15262
|
-
|
15265
|
+
const utils = this.app.create("utils");
|
15266
|
+
const cleaner = this.app.create("cleaner");
|
15263
15267
|
let text = utils.parseMarkdown(reply);
|
15264
15268
|
text = cleaner.store(text, "lists");
|
15265
15269
|
text = cleaner.store(text, "headings");
|
@@ -15278,19 +15282,19 @@ Redactor.add("plugin", "ai", {
|
|
15278
15282
|
_createPrompt(params) {
|
15279
15283
|
params = Redactor.extend(true, {}, { image: false }, params);
|
15280
15284
|
this.promptType = params.image ? "image" : "text";
|
15281
|
-
|
15282
|
-
|
15285
|
+
const placeholder = this.lang.get("ai.placeholder-" + this.promptType);
|
15286
|
+
const $editor = this.app.editor.getEditor();
|
15283
15287
|
$editor.find(".rx-ai-main").remove();
|
15284
|
-
|
15285
|
-
|
15286
|
-
|
15287
|
-
|
15288
|
+
const $main = this.dom('<div class="rx-in-tool rx-ai-main">').attr({ contenteditable: false });
|
15289
|
+
const $body = this.dom('<div class="rx-ai-body">');
|
15290
|
+
const $footer = this.dom('<div class="rx-ai-footer">');
|
15291
|
+
const $buttons = this.dom('<div class="rx-ai-buttons">');
|
15288
15292
|
this.$progress = this.dom('<div class="rx-ai-progress">');
|
15289
15293
|
this.$previewLabel = this.dom('<div class="rx-ai-preview-label">');
|
15290
15294
|
this.$preview = this.dom('<div class="rx-ai-preview">');
|
15291
15295
|
this.$prompt = this.dom('<div class="rx-ai-prompt">');
|
15292
15296
|
this.$label = this.dom('<label class="rx-ai-label">').html(this.lang.get("ai.prompt"));
|
15293
|
-
this.$textarea = this.dom('<textarea class="rx-ai-textarea rx-form-textarea">').attr({
|
15297
|
+
this.$textarea = this.dom('<textarea class="rx-ai-textarea rx-form-textarea">').attr({ placeholder });
|
15294
15298
|
this.$select = this.dom('<select class="rx-ai-select rx-form-select">');
|
15295
15299
|
this.$size = this.dom('<select class="rx-ai-size rx-form-select">');
|
15296
15300
|
this._createPromptFooter($footer, $buttons);
|
@@ -15318,14 +15322,14 @@ Redactor.add("plugin", "ai", {
|
|
15318
15322
|
return this.dom('<button class="rx-ai-button rx-form-button">').html(label);
|
15319
15323
|
},
|
15320
15324
|
_createSize($size) {
|
15321
|
-
|
15322
|
-
for (
|
15323
|
-
|
15325
|
+
const items = this.opts.get("ai.size");
|
15326
|
+
for (const [key, name] of Object.entries(items)) {
|
15327
|
+
const $option = this.dom("<option>").val(key).html(name);
|
15324
15328
|
$size.append($option);
|
15325
15329
|
}
|
15326
15330
|
},
|
15327
15331
|
_createTone($select) {
|
15328
|
-
|
15332
|
+
const items = this.promptType === "image" ? this.opts.get("ai.style") || this.defaults.style : this.opts.get("ai.tone") || this.defaults.tone;
|
15329
15333
|
let name = this.promptType === "image" ? this.lang.get("ai.image-style") : this.lang.get("ai.change-tone");
|
15330
15334
|
let $option = this.dom("<option>").val(0).html(name);
|
15331
15335
|
$select.append($option);
|
@@ -15349,19 +15353,20 @@ Redactor.add("plugin", "ai", {
|
|
15349
15353
|
},
|
15350
15354
|
_createSource(url, data) {
|
15351
15355
|
const eventTarget = new EventTarget();
|
15352
|
-
|
15356
|
+
const ajax = this.ajax.post({
|
15353
15357
|
url,
|
15354
15358
|
data,
|
15355
15359
|
before: function(xhr2) {
|
15356
|
-
|
15360
|
+
const event = this.app.broadcast("ai.before.send", { xhr: xhr2, data });
|
15357
15361
|
if (event.isStopped()) {
|
15358
15362
|
return false;
|
15359
15363
|
}
|
15360
15364
|
}.bind(this)
|
15361
15365
|
});
|
15362
|
-
|
15363
|
-
|
15364
|
-
|
15366
|
+
const xhr = ajax.xhr;
|
15367
|
+
const that = this;
|
15368
|
+
let ongoing = false;
|
15369
|
+
let start2 = 0;
|
15365
15370
|
xhr.onprogress = function() {
|
15366
15371
|
if (!ongoing) {
|
15367
15372
|
ongoing = true;
|
@@ -15373,7 +15378,7 @@ Redactor.add("plugin", "ai", {
|
|
15373
15378
|
}
|
15374
15379
|
let i, chunk;
|
15375
15380
|
if (that._isJsonString(xhr.responseText)) {
|
15376
|
-
|
15381
|
+
const response = JSON.parse(xhr.responseText);
|
15377
15382
|
if (response.error) {
|
15378
15383
|
that._error(response.error.message, response);
|
15379
15384
|
eventTarget.close();
|
@@ -15394,7 +15399,9 @@ Redactor.add("plugin", "ai", {
|
|
15394
15399
|
return eventTarget;
|
15395
15400
|
},
|
15396
15401
|
_isElementBottomBeyond(element) {
|
15397
|
-
|
15402
|
+
const $target = this.app.scroll.getTarget();
|
15403
|
+
const rect = element.getBoundingClientRect();
|
15404
|
+
const elementBottom = rect.top + rect.height;
|
15398
15405
|
return elementBottom > $target.get().innerHeight;
|
15399
15406
|
},
|
15400
15407
|
_isJsonString(str) {
|
@@ -15407,16 +15414,16 @@ Redactor.add("plugin", "ai", {
|
|
15407
15414
|
},
|
15408
15415
|
_insertAfterNode($tmp, content) {
|
15409
15416
|
let inserted;
|
15410
|
-
|
15411
|
-
|
15417
|
+
const instanceType = this.instance && this.instance.isType(["listitem", "todoitem"]);
|
15418
|
+
const event = this.app.broadcast("ai.before.insert", { html: content });
|
15412
15419
|
content = event.get("html");
|
15413
15420
|
if (instanceType) {
|
15414
15421
|
this.instance.setContent(content);
|
15415
15422
|
inserted = this.instance.getBlock();
|
15416
15423
|
} else {
|
15417
|
-
|
15418
|
-
|
15419
|
-
|
15424
|
+
const insertion = this.app.create("insertion");
|
15425
|
+
const node = this.app.block.create();
|
15426
|
+
const $node = node.getBlock();
|
15420
15427
|
content = this._parseReply(content);
|
15421
15428
|
$tmp.after($node);
|
15422
15429
|
$tmp.remove();
|
@@ -15426,7 +15433,7 @@ Redactor.add("plugin", "ai", {
|
|
15426
15433
|
this.app.broadcast("ai.insert", { nodes: inserted });
|
15427
15434
|
},
|
15428
15435
|
_insertPrompt($prompt, current, params) {
|
15429
|
-
|
15436
|
+
const elm = this.app.create("element");
|
15430
15437
|
let position = "after";
|
15431
15438
|
if (!current) {
|
15432
15439
|
if (this.opts.get("addPosition") === "top") {
|
@@ -15437,7 +15444,7 @@ Redactor.add("plugin", "ai", {
|
|
15437
15444
|
position = "after";
|
15438
15445
|
}
|
15439
15446
|
}
|
15440
|
-
|
15447
|
+
const $current = current.getBlock();
|
15441
15448
|
$current[position]($prompt);
|
15442
15449
|
elm.scrollTo($prompt);
|
15443
15450
|
this.app.observer.observeUnset();
|
@@ -15497,8 +15504,8 @@ Redactor.add("plugin", "ai", {
|
|
15497
15504
|
result += inCodeBlock ? this._escapeHtml(line) + "\n" : `<p>${this._escapeHtml(line)}</p>`;
|
15498
15505
|
}
|
15499
15506
|
}
|
15500
|
-
|
15501
|
-
|
15507
|
+
const bTag = tags.b ? tags.b : "b";
|
15508
|
+
const iTag = tags.i ? tags.i : "i";
|
15502
15509
|
result = result.replace(/\*\*\_(.*?)\_\*\*/g, "<" + bTag + "><" + iTag + ">$1</" + iTag + "></" + bTag + ">");
|
15503
15510
|
result = result.replace(/\*\*(.*?)\*\*/g, "<" + bTag + ">$1</" + bTag + ">");
|
15504
15511
|
result = result.replace(/\*(.*?)\*/g, "<" + iTag + ">$1</" + iTag + ">");
|
@@ -15506,7 +15513,7 @@ Redactor.add("plugin", "ai", {
|
|
15506
15513
|
},
|
15507
15514
|
_replaceCodeLine(line) {
|
15508
15515
|
return line.replace(/\`\`\`(([^\s]+))?/gm, function(match, p1, p2) {
|
15509
|
-
|
15516
|
+
const classAttribute = p2 ? ' class="' + p2 + '"' : "";
|
15510
15517
|
return "<pre" + classAttribute + "><code>";
|
15511
15518
|
});
|
15512
15519
|
},
|
@@ -15,6 +15,7 @@
|
|
15
15
|
# * +prepend+ - Display as input group with text on the left-hand side
|
16
16
|
# * +remote+ - Hash with all options for remote data fetching
|
17
17
|
# * +wrapper+ - Hash with all options for the surrounding html tag
|
18
|
+
# * +translatable+ - Adds a translatable icon next to the label if it is set to true. Defaults depends on initializer.
|
18
19
|
#
|
19
20
|
# ==== Remote options
|
20
21
|
# * +url+ -- JSON endpoint to fetch data from
|
@@ -11,6 +11,7 @@
|
|
11
11
|
# * +label+ - Text to display inside label tag. Defaults to the attribute name. Set to false if you don"t want to show a label.
|
12
12
|
# * +unchecked_value+ - Value for unchecked state
|
13
13
|
# * +wrapper+ - Hash with all options for the surrounding html tag
|
14
|
+
# * +translatable+ - Adds a translatable icon next to the label if it is set to true. Defaults depends on initializer.
|
14
15
|
#
|
15
16
|
# ==== References
|
16
17
|
# https://headmin.dev/docs/forms/checkbox
|
@@ -9,6 +9,7 @@
|
|
9
9
|
# * +hint+ - Informative text to assist with data input. HTML markup is allowed.
|
10
10
|
# * +label+ - Text to display inside label tag. Defaults to the attribute name. Set to false if you don"t want to show a label.
|
11
11
|
# * +wrapper+ - Hash with all options for the surrounding html tag
|
12
|
+
# * +translatable+ - Adds a translatable icon next to the label if it is set to true. Defaults depends on initializer.
|
12
13
|
#
|
13
14
|
# ==== References
|
14
15
|
# https://headmin.dev/docs/forms/color
|
@@ -14,6 +14,7 @@
|
|
14
14
|
# * +plaintext+ - Render input as plain text.
|
15
15
|
# * +prepend+ - Display as input group with text on the left-hand side
|
16
16
|
# * +wrapper+ - Hash with all options for the surrounding html tag
|
17
|
+
# * +translatable+ - Adds a translatable icon next to the label if it is set to true. Defaults depends on initializer.
|
17
18
|
#
|
18
19
|
# ==== References
|
19
20
|
# https://headmin.dev/docs/forms/date
|
@@ -15,6 +15,7 @@
|
|
15
15
|
# * +plaintext+ - Render input as plain text.
|
16
16
|
# * +prepend+ - Display as input group with text on the left-hand side
|
17
17
|
# * +wrapper+ - Hash with all options for the surrounding html tag
|
18
|
+
# * +translatable+ - Adds a translatable icon next to the label if it is set to true. Defaults depends on initializer.
|
18
19
|
#
|
19
20
|
# ==== References
|
20
21
|
# https://headmin.dev/docs/forms/email
|
@@ -15,6 +15,7 @@
|
|
15
15
|
# * +label+ - Text to display inside label tag. Defaults to the attribute name. Set to false if you don"t want to show a label.
|
16
16
|
# * +prepend+ - Display as input group with text on the left-hand side
|
17
17
|
# * +wrapper+ - Hash with all options for the surrounding html tag
|
18
|
+
# * +translatable+ - Adds a translatable icon next to the label if it is set to true. Defaults depends on initializer.
|
18
19
|
#
|
19
20
|
# ==== References
|
20
21
|
# https://headmin.dev/docs/forms/file
|