Browse Source

comboLookupModify

bohdan.kotenko 3 years ago
parent
commit
59abf6b911

+ 4 - 1
include/comboLookup.hrl

@@ -9,12 +9,15 @@
 -record(comboNext,   { pos=[],  count=[], feed=[]}).
 -record(comboScroll, { uid=[], dom=[], delegate=[] }).
 -record(comboInsert, { uid=[], dom=[], rows=[], chunks=[], status=[], delegate=[], feed=[] }).
+-record(comboAdd,    { list_id=[], value=[], bind=[], delegate=[], pos=[], feed=[] }).
+-record(comboModify, { list_id=[], item_id=[], value=[], bind=[], modify_bind=[], delegate=[], pos=[], feed=[] }).
 -record(comboLookup, { ?ELEMENT_BASE(element_comboLookup),
     value=[],
     disabled=false,
     feed=[],
     reader=[],
-    chunk=20 }).
+    chunk=20,
+    nested=[] }).
 
 -record(process, {name=[]}).
 

+ 9 - 0
include/comboLookupModify.hrl

@@ -0,0 +1,9 @@
+-ifndef(COMBO_LOOKUP_MODIFY_HRL).
+-define(COMBO_LOOKUP_MODIFY_HRL, true).
+
+-include_lib("nitro/include/nitro.hrl").
+
+-record(comboLookupModify, {?ELEMENT_BASE(element_comboLookupModify), input = [], disabled = false,
+                            values = [], modify_pos = [], modify_feed = [], modify_module = []}).
+
+-endif.

+ 9 - 0
include/comboLookupModify_item.hrl

@@ -0,0 +1,9 @@
+-ifndef(COMBO_LOOKUP_MODIFY_ITEM_HRL).
+-define(COMBO_LOOKUP_MODIFY_ITEM_HRL, true).
+
+-include_lib("nitro/include/nitro.hrl").
+
+-record(comboLookupModify_item, {?ELEMENT_BASE(element_comboLookupModify_item), list_id = [], value = [],
+                                 pos = [], feed = [], disabled = false}).
+
+-endif.

+ 2 - 2
lib/NITRO.ex

@@ -1,8 +1,8 @@
 defmodule NITRO do
   require Record
 
-  files = ["calendar.hrl", "nitro.hrl", "comboLookup.hrl", "nitro_pi.hrl",
-           "comboLookupVec.hrl", "comboLookupEdit.hrl", "koatuuControl.hrl", "n2o.hrl"]
+  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"]
 
   hrl_files =
     Enum.filter(files, fn f ->

+ 31 - 0
lib/combo.ex

@@ -15,6 +15,8 @@ defmodule NITRO.Combo do
   def proto(NITRO.comboKey(delegate: []) = msg), do: NITRO.Combo.Search.keyUp(msg)
   def proto(NITRO.comboScroll(delegate: []) = msg), do: NITRO.Combo.Search.comboScroll(msg)
   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.comboKey(delegate: module) = msg) do
     case has_function(module, :keyUp) do
@@ -44,6 +46,20 @@ defmodule NITRO.Combo do
     end
   end
 
+  def proto(NITRO.comboAdd(delegate: module) = msg) do
+    case has_function(module, :comboAdd) do
+      true -> module.comboAdd(msg)
+      false -> comboAdd(msg)
+    end
+  end
+
+  def proto(NITRO.comboModify(delegate: module) = msg) do
+    case has_function(module, :comboModify) do
+      true -> module.comboModify(msg)
+      false -> comboModify(msg)
+    end
+  end
+
   def select(NITRO.comboSelect(uid: uid, dom: field)), do:
     NITRO.Combo.Search.stop(uid, field)
 
@@ -62,6 +78,21 @@ defmodule NITRO.Combo do
     end, rows)
   end
 
+  def comboAdd(NITRO.comboAdd(list_id: list, value: value, bind: bind, delegate: module, pos: pos, feed: feed)) do
+    :nitro.insert_bottom(
+      list,
+      NITRO.comboLookupModify_item(list_id: list, value: value, bind: bind, pos: pos, feed: feed, delegate: module)
+    )
+  end
+
+  def comboModify(NITRO.comboModify(list_id: list, item_id: item, value: value, bind: bind, modify_bind: modify_bind, delegate: module, pos: pos, feed: feed)) do
+    new_bind = :erlang.setelement(pos, bind, modify_bind)
+    :nitro.update(
+      item,
+      NITRO.comboLookupModify_item(list_id: list, value: value, bind: new_bind, pos: pos, feed: feed, delegate: module)
+    )
+  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.2.1",
+      version: "7.4.0",
       description: "NITRO Nitrogen Web Framework",
       package: package(),
       deps: deps()

+ 4 - 2
priv/css/sortable.css

@@ -106,7 +106,8 @@ body {
 }
 
 .add-btn,
-.delete-btn {
+.delete-btn,
+.modify_item-close {
   position: absolute;
   top: 8px;
   right: 10px;
@@ -120,7 +121,8 @@ body {
   background-color: #ffffff;
 }
 
-.delete-btn {
+.delete-btn,
+.modify_item-close {
   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;
 }

+ 48 - 6
priv/js/comboLookup.js

@@ -52,12 +52,21 @@ function comboSelect(uid, dom, row, feed, mod, id) {
     dropdown.classList.remove('is-reversed');
     dropdown.classList.add('dropdown-bind');
     let value = qi(id) ? dec(unbase64(qi(id).getAttribute('data-bind'))) : string(row);
-    direct(tuple(atom('comboSelect'),
-                 bin(uid),
-                 value,
-                 string(dom),
-                 string(feed),
-                 atom(mod)));
+    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)));
+    }
     comboLookupTextApply(dom);
 }
 
@@ -167,6 +176,39 @@ function clearInput(dom) {
   comboClear(dom);
 }
 
+function comboLookupModifyAdd(listId, inputId) {
+  const input = qi(inputId);
+  const list = qi(listId);
+  if (list && input && input.value != '') {
+    const data = querySourceRaw(inputId);
+    if (data && data.hasOwnProperty('text') && data.hasOwnProperty('bind')) {
+      const bind = data.bind;
+      const value = data.text;
+      if (bind !== '' && bind !== 'null') {
+        clearInput(inputId);
+        direct(tuple(atom('comboAdd'),
+                     string(listId),
+                     string(value),
+                     dec(unbase64(bind)),
+                     dec(unbase64(list.getAttribute('data-delegate'))),
+                     dec(unbase64(list.getAttribute('data-pos'))),
+                     dec(unbase64(list.getAttribute('data-feed')))));
+      }
+    }
+  }
+}
+
+function comboLookupModifyValues(listId) {
+  const list = qi(listId);
+  if (list) {
+    return Array.from(list.children).map(function (el) {
+      return {'text': el.firstChild.innerHTML, 'bind': el.getAttribute('data-bind')}
+    })
+  } else {
+    return []
+  }
+}
+
 document.addEventListener("click", () => {
   if (activeCombo && event.target.className != 'triangle' &&
     !event.target.closest('#comboContainer_' + activeCombo)) {

+ 4 - 0
priv/js/nitro.js

@@ -42,6 +42,8 @@ function querySourceRaw(Id) {
             }
             else if (el.getAttribute('data-vector-input')) {
                 val = querySourceRaw(el.children[1].id);
+            } else if (el.getAttribute('data-modify-input')) {
+                val = querySourceRaw(el.children[1].id);
             } else if (el.getAttribute('data-edit-input')) {
                 let sortableList = el.children[1];
                 let sourceRaw = sortableList ? sortableList.id :
@@ -49,6 +51,8 @@ function querySourceRaw(Id) {
                 val = querySourceRaw(sourceRaw);
             } else if (el.getAttribute('data-sortable-list')) {
                 val = getSortableValues('#' + el.id);
+            } else if (el.getAttribute('data-modify-list')) {
+                val = comboLookupModifyValues(el.id);
             } else if (el.contentEditable === 'true') {
                 val = el.innerHTML;
             } else {

+ 9 - 2
src/elements/combo/element_comboLookup.erl

@@ -7,15 +7,22 @@ proto(#comboKey{delegate=Module}=Msg)    -> Module:proto(Msg);
 proto(#comboKeyup{delegate=Module}=Msg)  -> Module:proto(Msg);
 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(#comboInsert{delegate=Module}=Msg) -> Module:proto(Msg);
+proto(#comboAdd{delegate=Module}=Msg)    -> Module:proto(Msg);
+proto(#comboModify{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} = Data) ->
+  feed = Feed, disabled = Disabled, delegate = Module, class = Class, nested = Nested} = Data) ->
   Uid = nitro_pi:uid([], []),
   nitro:render(
     #panel{id=form:atom([lookup, Id]), class=lists:flatten([dropdown, Class]),
            body=[#input{id=Id, disabled = Disabled, type="comboLookup",
                         autocomplete = "off",
+                        data_fields =
+                          case Nested of
+                            [] -> [];
+                            X -> [{<<"nested">>, X}]
+                          end,
                         onkeyup = nitro:jse("comboLookupKeyup('"
                                ++ nitro:to_list(Uid) ++ "','"
                                ++ nitro:to_list(Id) ++ "','"

+ 47 - 0
src/elements/combo/element_comboLookupModify.erl

@@ -0,0 +1,47 @@
+-module(element_comboLookupModify).
+-include_lib("nitro/include/comboLookupModify.hrl").
+-include_lib("nitro/include/comboLookupModify_item.hrl").
+-include_lib("nitro/include/nitro.hrl").
+-include_lib("nitro/include/event.hrl").
+-export([render_element/1]).
+
+render_element(#comboLookupModify{id = Id, input = Input, disabled = Disabled, validation = Validation, values = Values, modify_pos = Pos, modify_feed = Feed, modify_module = Module}) ->
+  ListId = form:atom([Id, "list"]),
+  InputId = element(#element.id, Input),
+  InputBody =
+    case Disabled of
+      true -> [];
+      _ ->
+        #panel{
+          body = [
+            Input,
+            #link{class = 'add-btn', onclick = nitro:jse("comboLookupModifyAdd('" ++ ListId ++ "', '" ++ InputId ++ "');")}
+          ]
+        }
+    end,
+  ProtoItem = #comboLookupModify_item{list_id = ListId, pos = Pos, feed = Feed, delegate = Module, disabled = Disabled},
+  ListBody =
+    case Values of
+      {view_value_pairs, X} -> [ProtoItem#comboLookupModify_item{value = Value, bind = Bind} || {Value, Bind} <- X];
+      _ -> [ProtoItem#comboLookupModify_item{value = X} || X <- Values]
+    end,
+  nitro:render(
+    #panel{
+      id = Id,
+      data_fields = [{<<"data-modify-input">>, <<"data-modify-input">>}],
+      validation = Validation,
+      body = [
+        InputBody,
+        #panel{
+          id = ListId,
+          data_fields = [
+            {<<"data-modify-list">>, <<"data-modify-list">>},
+            {<<"data-pos">>, base64:encode(term_to_binary(Pos))},
+            {<<"data-feed">>, base64:encode(term_to_binary(Feed))},
+            {<<"data-delegate">>, base64:encode(term_to_binary(Module))}
+          ],
+          body = ListBody
+        }
+      ]
+    }
+  ).

+ 32 - 0
src/elements/combo/element_comboLookupModify_item.erl

@@ -0,0 +1,32 @@
+-module(element_comboLookupModify_item).
+-include_lib("nitro/include/comboLookupModify_item.hrl").
+-include_lib("nitro/include/comboLookup.hrl").
+-include_lib("nitro/include/nitro.hrl").
+-include_lib("nitro/include/event.hrl").
+-export([render_element/1]).
+
+render_element(#comboLookupModify_item{list_id = ListId, value = Value, bind = Bind, pos = Pos, feed = Feed, delegate = Module, disabled = Disabled}) ->
+  Id = form:atom([ListId, erp:guid()]),
+  Close =
+    case Disabled of
+      true -> [];
+      _ -> #panel{class = <<"modify_item-close">>, onclick = nitro:jse("this.parentNode.remove();")}
+    end,
+  Selected =
+    case erlang:function_exported(Module, view_value, 1) of
+      true -> apply(Module, view_value, [element(Pos, Bind)]);
+      false -> []
+    end,
+  nitro:render(
+    #panel{
+      id = Id,
+      class = <<"modify_item">>,
+      data_fields = [{<<"data-bind">>, base64:encode(term_to_binary(Bind))}],
+      body = [
+        #panel{class = <<"modify_item-title">>, body = Value},
+        Close,
+        #comboLookup{id = form:atom([Id, "input"]), feed = Feed, delegate = Module, value = Selected, nested = Id, disabled = Disabled}
+      ]
+    }
+  ).
+