5HT 3 лет назад
Родитель
Сommit
33d7e43a16

+ 2 - 0
include/comboLookup.hrl

@@ -11,6 +11,8 @@
 -record(comboInsert, { uid=[], dom=[], rows=[], chunks=[], status=[], delegate=[], feed=[] }).
 -record(comboAdd,    { list_id=[], value=[], bind=[], delegate=[], pos=[], feed=[], default=[]}).
 -record(comboModify, { list_id=[], item_id=[], value=[], bind=[], modify_bind=[], delegate=[], pos=[], feed=[] }).
+-record(comboGroup,  { dom=[], value=[], delegate=[] }).
+-record(comboDraft,  { dom=[], list=[], values=[], group=[], subtitle=[], delegate=[] }).
 -record(comboLookup, { ?ELEMENT_BASE(element_comboLookup),
     value=[],
     disabled=false,

+ 2 - 1
lib/NITRO.ex

@@ -2,7 +2,8 @@ defmodule NITRO do
   require Record
 
   files = ["calendar.hrl", "nitro.hrl", "comboLookup.hrl", "nitro_pi.hrl", "comboLookupVec.hrl", "comboLookupEdit.hrl",
-           "comboLookupText.hrl", "comboLookupModify.hrl", "comboLookupModify_item.hrl", "koatuuControl.hrl", "n2o.hrl"]
+           "comboLookupText.hrl", "comboLookupModify.hrl", "comboLookupModify_item.hrl", "comboLookupGroup.hrl",
+           "comboLookupGroup_list.hrl", "comboLookupGroup_item.hrl", "koatuuControl.hrl", "n2o.hrl"]
 
   hrl_files =
     Enum.filter(files, fn f ->

+ 39 - 0
lib/combo.ex

@@ -17,6 +17,8 @@ defmodule NITRO.Combo do
   def proto(NITRO.comboInsert(delegate: []) = msg), do: comboInsert(msg)
   def proto(NITRO.comboAdd(delegate: []) = msg), do: comboAdd(msg)
   def proto(NITRO.comboModify(delegate: []) = msg), do: comboModify(msg)
+  def proto(NITRO.comboGroup(delegate: []) = msg), do: comboGroup(msg)
+  def proto(NITRO.comboDraft(delegate: []) = msg), do: comboDraft(msg)
 
   def proto(NITRO.comboKey(delegate: module) = msg) do
     case has_function(module, :keyUp) do
@@ -60,6 +62,20 @@ defmodule NITRO.Combo do
     end
   end
 
+  def proto(NITRO.comboGroup(delegate: module) = msg) do
+    case has_function(module, :comboGroup) do
+      true -> module.comboGroup(msg)
+      false -> comboGroup(msg)
+    end
+  end
+
+  def proto(NITRO.comboDraft(delegate: module) = msg) do
+    case has_function(module, :comboDraft) do
+      true -> module.comboDraft(msg)
+      false -> comboDraft(msg)
+    end
+  end
+
   def select(NITRO.comboSelect(uid: uid, dom: field)), do:
     NITRO.Combo.Search.stop(uid, field)
 
@@ -93,6 +109,29 @@ defmodule NITRO.Combo do
     )
   end
 
+  def comboGroup(NITRO.comboGroup(dom: dom, value: value, delegate: module)) do
+    :nitro.insert_bottom(
+      dom,
+      NITRO.comboLookupGroup_item(value: view_value(value, module, []), bind: value, group: :draft)
+    )
+  end
+
+  def comboDraft(NITRO.comboDraft(values: [])), do: []
+  def comboDraft(NITRO.comboDraft(dom: dom, list: list_id, values: values, group: group, subtitle: subtitle, delegate: module)) do
+    value_pairs = {:view_value_pairs, :lists.map(fn val -> {view_value(val, module, []), val} end, values)}
+    proto_item = NITRO.comboLookupGroup_list(subtitle: subtitle, delegate: module)
+    draft_id = :form.atom([dom, :draft])
+
+    case group do
+      :draft ->
+        :nitro.update(draft_id, NITRO.comboLookupGroup_list(proto_item, id: draft_id, group: :draft))
+        :nitro.insert_after(draft_id, NITRO.comboLookupGroup_list(proto_item, id: :form.atom([dom, :erp.guid()]), values: value_pairs, group: :saved))
+      _ ->
+        :nitro.update(draft_id, NITRO.comboLookupGroup_list(proto_item, id: draft_id, values: value_pairs, group: :draft))
+        :nitro.remove(list_id)
+    end
+  end
+
   def dropDown0(uid, obj, dom0, module, feed) do
     case has_function(module, :dropDown) do
       true ->

+ 1 - 1
mix.exs

@@ -4,7 +4,7 @@ defmodule NITRO.Mixfile do
   def project do
     [
       app: :nitro,
-      version: "7.6.0",
+      version: "7.6.2",
       description: "NITRO Nitrogen Web Framework",
       package: package(),
       deps: deps()

+ 14 - 2
priv/css/sortable.css

@@ -107,7 +107,10 @@ body {
 
 .add-btn,
 .delete-btn,
-.modify_item-close {
+.modify_item-close,
+.group-button__confirm,
+.group-button__delete,
+.group-button__edit {
   position: absolute;
   top: 8px;
   right: 10px;
@@ -122,7 +125,16 @@ body {
 }
 
 .delete-btn,
-.modify_item-close {
+.modify_item-close,
+.group-button__delete {
   background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.6666 4.27325L11.7266 3.33325L7.99992 7.05992L4.27325 3.33325L3.33325 4.27325L7.05992 7.99992L3.33325 11.7266L4.27325 12.6666L7.99992 8.93992L11.7266 12.6666L12.6666 11.7266L8.93992 7.99992L12.6666 4.27325Z' fill='%23757575'/%3E%3C/svg%3E%0A");
   right: 30px;
+}
+
+.group-button__confirm {
+  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1 8a7 7 0 1 1 14 0A7 7 0 0 1 1 8Zm6 1 4-4 1 1-5 5-3-2 1-1 2 1Z' fill='%230D63B3'/%3E%3C/svg%3E");
+}
+
+.group-button__edit {
+  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='m12.246 2.193 1.56 1.56c.26.26.26.68 0 .94l-1.22 1.22-2.5-2.5 1.22-1.22A.656.656 0 0 1 11.772 2c.174 0 .34.06.474.193ZM1.999 11.5V14h2.5l7.373-7.373-2.5-2.5L2 11.5Zm1.947 1.167h-.614v-.614l6.04-6.04.614.614-6.04 6.04Z' fill='%23757575'/%3E%3C/svg%3E");
 }

+ 89 - 25
priv/js/comboLookup.js

@@ -42,32 +42,72 @@ function comboClear(dom) {
 }
 
 function comboSelect(uid, dom, row, feed, mod, id) {
-    let elem = qi(dom);
-    comboClear(dom);
-    if (qi(id)) elem.setAttribute("data-bind", qi(id).getAttribute('data-bind'));
-    elem.value = row;
-    elem.style.backgroundColor = 'white';
-    var dropdown = qi(dom).closest('.dropdown');
-    dropdown.classList.remove('dropdown-open');
-    dropdown.classList.remove('is-reversed');
-    dropdown.classList.add('dropdown-bind');
-    let value = qi(id) ? dec(unbase64(qi(id).getAttribute('data-bind'))) : string(row);
-    const modifyItem = qi(elem.getAttribute('nested'));
-    if (modifyItem) {
-      const list = modifyItem.parentNode;
-      direct(tuple(atom('comboModify'),
-                   string(list.id),
-                   string(modifyItem.id),
-                   string(modifyItem.firstChild.innerHTML),
-                   dec(unbase64(modifyItem.getAttribute('data-bind'))),
-                   value,
-                   dec(unbase64(list.getAttribute('data-delegate'))),
-                   dec(unbase64(list.getAttribute('data-pos'))),
-                   dec(unbase64(list.getAttribute('data-feed')))));
-    } else {
-      direct(tuple(atom('comboSelect'), bin(uid), value, string(dom), string(feed), atom(mod)));
+  let elem = qi(dom);
+  elem.value = '';
+  comboClear(dom);
+
+  if (qi(elem.getAttribute('nested'))) {
+    comboSelectModify(...arguments);
+  } else if (elem.parentNode.parentNode.parentNode.getAttribute('data-vector-input')) {
+    comboSelectVector(...arguments);
+  } else if (elem.parentNode.parentNode.getAttribute('data-group-input')) {
+    comboSelectGroup(...arguments);
+  } else {
+    comboSelectDefault(...arguments);
+  }
+}
+
+function comboSelectDefault(uid, dom, row, feed, mod, id) {
+  let elem = qi(dom);
+  elem.closest('.dropdown').classList.add('dropdown-bind')
+  elem.value = row;
+
+  let value = string(row);
+  const selected = qi(id);
+  if (selected) {
+    elem.setAttribute('data-bind', selected.getAttribute('data-bind'));
+    value = dec(unbase64(selected.getAttribute('data-bind')));
+  }
+
+  direct(tuple(atom('comboSelect'), bin(uid), value, string(dom), string(feed), atom(mod)));
+  comboLookupTextApply(dom);
+};
+
+function comboSelectModify(uid, dom, row, feed, mod, id) {
+  const modifyItem = qi(qi(dom).getAttribute('nested'));
+  const list = modifyItem.parentNode;
+  const value = qi(id) ? dec(unbase64(qi(id).getAttribute('data-bind'))) : string(row)
+
+  direct(tuple(atom('comboModify'),
+               string(list.id),
+               string(modifyItem.id),
+               string(modifyItem.firstChild.innerHTML),
+               dec(unbase64(modifyItem.getAttribute('data-bind'))),
+               value,
+               dec(unbase64(list.getAttribute('data-delegate'))),
+               dec(unbase64(list.getAttribute('data-pos'))),
+               dec(unbase64(list.getAttribute('data-feed')))));
+}
+
+function comboSelectVector(uid, dom, row, feed, mod, id) {
+  comboSelectDefault(...arguments);
+  let listSplit = dom.split('_');
+  listSplit.pop();
+  const list = '#' + listSplit.join('_') + '_list';
+  addSortableItemFrom(list, dom);
+}
+
+function comboSelectGroup(uid, dom, row, feed, mod, id) {
+  const selected = qi(id);
+  if (selected) {
+    const parent = qi(dom).parentNode.parentNode;
+    const bind = selected.getAttribute('data-bind');
+    if (!parent.querySelector(`[data-group-item='data-group-item'][data-bind='${bind}']`)) {
+      const draft = parent.id + '_draft';
+      const value = dec(unbase64(bind));
+      direct(tuple(atom('comboGroup'), string(draft), value, atom(mod)));
     }
-    comboLookupTextApply(dom);
+  }
 }
 
 function comboLookupChange(dom) {
@@ -210,6 +250,30 @@ function comboLookupModifyValues(listId) {
   }
 }
 
+function comboLookupGroupDraft(id, group, subtitle, mod) {
+  const elem = qi(id);
+  const values = Array.from(elem.querySelectorAll('[data-group-item]')).map(function (el) {return dec(unbase64(el.getAttribute('data-bind')))});
+  direct(tuple(atom('comboDraft'), string(elem.parentNode.id), string(id), values, atom(group), bin(subtitle), atom(mod)));
+}
+
+function groupListDrag(e) { e.dataTransfer.setData('text', e.target.id); }
+
+function groupListDrop(e) {
+  e.preventDefault();
+  const node1 = e.currentTarget;
+  const node2 = qi(e.dataTransfer.getData('text'));
+  const parent = node1.parentNode;
+  const sibling = node1.nextSibling === node2 ? node1 : node1.nextSibling;
+
+  node2.parentNode.insertBefore(node1, node2);
+  parent.insertBefore(node2, sibling);
+}
+
+function groupListAllowDrop(e) {
+  e.preventDefault();
+  e.dataTransfer.dropEffect = 'move';
+}
+
 document.addEventListener("click", () => {
   if (activeCombo && event.target.className != 'triangle' &&
     !event.target.closest('#comboContainer_' + activeCombo)) {

+ 3 - 1
src/elements/combo/element_comboLookup.erl

@@ -9,7 +9,9 @@ proto(#comboSelect{delegate=Module}=Msg) -> Module:proto(Msg);
 proto(#comboScroll{delegate=Module}=Msg) -> Module:proto(Msg);
 proto(#comboInsert{delegate=Module}=Msg) -> Module:proto(Msg);
 proto(#comboAdd{delegate=Module}=Msg)    -> Module:proto(Msg);
-proto(#comboModify{delegate=Module}=Msg) -> Module:proto(Msg).
+proto(#comboModify{delegate=Module}=Msg) -> Module:proto(Msg);
+proto(#comboGroup{delegate=Module}=Msg)  -> Module:proto(Msg);
+proto(#comboDraft{delegate=Module}=Msg)  -> Module:proto(Msg).
 
 render_element(#comboLookup{id=Id, style=Style, value = Val, bind = Object,
   feed = Feed, disabled = Disabled, delegate = Module, class = Class, nested = Nested} = Data) ->

+ 1 - 7
src/elements/combo/element_comboLookupVec.erl

@@ -19,13 +19,7 @@ render_element(#comboLookupVec{id=Id, input=Input, disabled=Disabled, validation
           body =
             case Disabled of
               true -> [];
-              _ ->
-                [ Input,
-                  #link{
-                    class = [button, sgreen, 'add-btn'],
-                    style = "min-width: 40px; text-align: center; height: fit-content; margin-left: 5px;",
-                    onclick = nitro:jse("addSortableItemFrom('#" ++ ListId ++ "', '" ++ InputId ++ "')"),
-                    body = <<"+">>} ] end },
+              _ -> Input end },
         % TODO: Add validation for each list_item and/or "+" button
         % TODO?: Maybe show message "Empty list" when Values == []
         #sortable_list{id = ListId, values = Values, closeable = true, disabled = Disabled}]}).

+ 1 - 1
src/nitro.app.src

@@ -1,6 +1,6 @@
 {application, nitro, [
     {description,  "NITRO Nitrogen Web Framework"},
-    {vsn,          "7.5.0"},
+    {vsn,          "7.6.2"},
     {applications, [kernel, stdlib]},
     {modules, []},
     {registered,   []},