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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/formstrap/controllers/media_controller.js +8 -4
  3. data/app/assets/javascripts/formstrap/vendor/redactor/i18n/nl.js +1 -1
  4. data/app/assets/javascripts/formstrap/vendor/redactor/plugins/ai.js +958 -982
  5. data/app/assets/javascripts/formstrap/vendor/redactor/plugins/linkstyles.js +2 -2
  6. data/app/assets/javascripts/formstrap.js +105 -98
  7. data/app/models/concerns/formstrap/labelable.rb +2 -1
  8. data/app/views/formstrap/_association.html.erb +1 -0
  9. data/app/views/formstrap/_checkbox.html.erb +1 -0
  10. data/app/views/formstrap/_color.html.erb +1 -0
  11. data/app/views/formstrap/_date.html.erb +1 -0
  12. data/app/views/formstrap/_email.html.erb +1 -0
  13. data/app/views/formstrap/_file.html.erb +1 -0
  14. data/app/views/formstrap/_label.html.erb +5 -0
  15. data/app/views/formstrap/_media.html.erb +2 -1
  16. data/app/views/formstrap/_number.html.erb +1 -0
  17. data/app/views/formstrap/_password.html.erb +1 -0
  18. data/app/views/formstrap/_redactor.html.erb +1 -0
  19. data/app/views/formstrap/_select.html.erb +1 -0
  20. data/app/views/formstrap/_switch.html.erb +2 -1
  21. data/app/views/formstrap/_text.html.erb +2 -1
  22. data/app/views/formstrap/_textarea.html.erb +1 -0
  23. data/app/views/formstrap/_wysiwyg.html.erb +1 -0
  24. data/config/locales/formstrap/de.yml +2 -0
  25. data/config/locales/formstrap/en.yml +2 -0
  26. data/config/locales/formstrap/fr.yml +2 -0
  27. data/config/locales/formstrap/nl.yml +2 -0
  28. data/lib/formstrap/version.rb +1 -1
  29. data/package.json +1 -1
  30. metadata +2 -3
  31. 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.params.element.nodes[0]
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.params.element.nodes[0]
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
- if (this.activeItems().length > 0) {
11208
- this.hidePlaceholder();
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("beforeend", templateHtml);
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.params.element.nodes[0];
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.params.element.nodes[0];
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
- "ai": {
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
- "send": "Send",
14690
- "stop": "Stop",
14691
- "discard": "Discard",
14692
- "insert": "Insert",
14693
- "prompt": "Prompt",
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
- let uiState = this.app.ui.getState();
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
- let buttons = {};
14787
- let items = this.opts.get("ai.tone") || this.defaults.tone;
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
- let buttons = {};
14797
- let items = this.opts.get("ai.translate") || this.defaults.translate;
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
- let event = this.app.broadcast("ai.create", { prompt: message });
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
- let apimodel = this.opts.get("ai." + this.promptType + ".model");
14827
+ const apimodel = this.opts.get("ai." + this.promptType + ".model");
14827
14828
  let message = this._getMessage();
14828
- let event = this.app.broadcast("ai.create", { prompt: message });
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
- let tone = this._getTone(message);
14834
+ const tone = this._getTone(message);
14834
14835
  if (this.promptType === "text") {
14835
- this.conversation.push({ "role": "user", "content": message });
14836
+ this.conversation.push({ role: "user", content: message });
14836
14837
  if (tone) {
14837
- this.conversation.push({ "role": "user", "content": tone });
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
- let insertion = this.app.create("insertion");
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
- let event = this.app.broadcast("ai.before.insert", { html });
14867
+ const event = this.app.broadcast("ai.before.insert", { html });
14867
14868
  html = event.get("html");
14868
- let $target = this.savedInstance ? this.savedInstance.getBlock() : this.$prompt;
14869
- let position = this.savedInstance ? "after" : "before";
14870
- let remove = this.savedInstance ? false : true;
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
- let inserted = insertion.insert({ html, target: $target, position, remove });
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
- let eventName = e ? "ai.stop" : "ai.complete";
14894
- let prompt = this.$previewLabel.text();
14895
- let result = e ? { prompt } : { prompt, response: this._parseReply(reply) };
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
- let tone = this.$select.val();
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
- let instance = this.app.block.get();
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
- let instance = this.app.block.get();
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
- let type = instances[i].getType(), prefix = type === "listitem" ? "- " : "";
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
- let node = this.app.block.create();
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
- let messages = [{ "role": "user", "content": text }, { "role": "user", "content": prompt }];
14967
- let request = {
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
- let $node = this._getInsertedNode();
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
- let event = this.app.broadcast("ai.before.send", { xhr, data });
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
- let request = {
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
- let source = this._createSource(serverurl, data);
15019
+ const source = this._createSource(serverurl, data);
15018
15020
  this.isEvent = source;
15019
15021
  this.currentIndex = 0;
15020
- let $target = this.app.scroll.getTarget();
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
- let message2 = event.data, start2 = message2.indexOf(": ", "data") + 2, data2 = message2.slice(start2, message2.length);
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
- let content = choices[0].delta.content;
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
- let checkInterval = setInterval(function() {
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({ "role": "assistant", "content": responseContent });
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
- let value = this.modifiedValue || this.$textarea.val();
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
- let isAll = this.app.editor.isSelectAll();
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
- let $first = this.app.blocks.get({ first: true });
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
- let isMultiple = this.app.blocks.is();
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
- let $parent = instance.getBlock().closest("[data-rx-type=" + types.join("],[data-rx-type=") + "]");
15135
- let $column = instance.getBlock().closest("[data-rx-type=column]");
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
- let $node = this.app.editor.getEditor().find(".rx-inserted-node");
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
- let insertion = this.app.create("insertion");
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 ? error2 : response);
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
- let reply = response.choices[0].message.content;
15176
+ const reply = response.choices[0].message.content;
15173
15177
  let html = this._parseReply(reply);
15174
- let insertion = this.app.create("insertion");
15175
- let event = this.app.broadcast("ai.before.insert", { html });
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
- let instanceType = this.instance && this.instance.isType(["listitem", "todoitem"]);
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
- let $node = this._getNode();
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
- let value = this.modifiedValue || this.$textarea.val();
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
- let prompt = this.$previewLabel.text();
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
- let event = this.app.broadcast("ai.before.save", { xhr, data });
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
- let $image = this.dom("<img>").attr("src", imageUrl);
15253
- let result = $image.get().outerHTML;
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
- let prompt = this.$previewLabel.text();
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
- let utils = this.app.create("utils");
15262
- let cleaner = this.app.create("cleaner");
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
- let placeholder = this.lang.get("ai.placeholder-" + this.promptType);
15282
- let $editor = this.app.editor.getEditor();
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
- let $main = this.dom('<div class="rx-in-tool rx-ai-main">').attr({ "contenteditable": false });
15285
- let $body = this.dom('<div class="rx-ai-body">');
15286
- let $footer = this.dom('<div class="rx-ai-footer">');
15287
- let $buttons = this.dom('<div class="rx-ai-buttons">');
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({ "placeholder": placeholder });
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
- let items = this.opts.get("ai.size");
15322
- for (let [key, name] of Object.entries(items)) {
15323
- let $option = this.dom("<option>").val(key).html(name);
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
- let items = this.promptType === "image" ? this.opts.get("ai.style") || this.defaults.style : this.opts.get("ai.tone") || this.defaults.tone;
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
- let ajax = this.ajax.post({
15356
+ const ajax = this.ajax.post({
15353
15357
  url,
15354
15358
  data,
15355
15359
  before: function(xhr2) {
15356
- let event = this.app.broadcast("ai.before.send", { xhr: xhr2, data });
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
- let xhr = ajax.xhr;
15363
- let that = this;
15364
- var ongoing = false, start2 = 0;
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
- let response = JSON.parse(xhr.responseText);
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
- let $target = this.app.scroll.getTarget(), rect = element.getBoundingClientRect(), elementBottom = rect.top + rect.height;
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
- let instanceType = this.instance && this.instance.isType(["listitem", "todoitem"]);
15411
- let event = this.app.broadcast("ai.before.insert", { html: content });
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
- let insertion = this.app.create("insertion");
15418
- let node = this.app.block.create();
15419
- let $node = node.getBlock();
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
- let elm = this.app.create("element");
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
- let $current = current.getBlock();
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
- let bTag = tags.b ? tags.b : "b";
15501
- let iTag = tags.i ? tags.i : "i";
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
- let classAttribute = p2 ? ' class="' + p2 + '"' : "";
15516
+ const classAttribute = p2 ? ' class="' + p2 + '"' : "";
15510
15517
  return "<pre" + classAttribute + "><code>";
15511
15518
  });
15512
15519
  },
@@ -23,7 +23,8 @@ module Formstrap
23
23
  attribute: attribute,
24
24
  form: form,
25
25
  required: required,
26
- text: label
26
+ text: label,
27
+ translatable: translatable
27
28
  }
28
29
  end
29
30
  end
@@ -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