index.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. function nbInit($s){
  2. function nBind(callback, prop, direction){
  3. direction = direction || "write";
  4. for (var selector in $s){
  5. var result = [];
  6. selector = prop || selector; //change selector to passed if it
  7. var items = [document.getElementById(selector)];
  8. items = items[0] ? items : document.querySelectorAll(selector);
  9. items = items.length ? items : document.getElementsByName(selector);
  10. items = items.length ? items : document.getElementsByClassName(selector);
  11. for (var i=0,item=items[i];i<items.length;i++,item=items[i]){
  12. if (direction == "write" && item.children.length == 0 && Array.isArray($s[selector])){
  13. callback(item, $s, selector, $s[selector][i]);
  14. }
  15. else {
  16. var res = callback(item, $s, selector);
  17. if (typeof res !== "undefined"){
  18. result.push(res)
  19. }
  20. }
  21. }
  22. $s[selector] = result.length ? (result.length == 1 ? result[0] : result) : $s[selector];
  23. if (prop) return; //exit if selector passed, no iteration
  24. }
  25. }
  26. function syncToDOM(prop){
  27. nBind(function (item, $s, selector, value, key){
  28. value = typeof value === 'undefined' ? $s[selector] : value;
  29. var keyExists = typeof key !== 'undefined';
  30. if (!item.children.length && !Array.isArray(value) && typeof value === 'object'){ //hash array on single leaf node -> set attrs on the tag
  31. for (var key in value){
  32. item[key] = value[key];
  33. }
  34. return;
  35. }
  36. if (keyExists && "value" in item){ //if hash key-value pair. Usable for select > option
  37. item.value = key;
  38. }
  39. if (typeof value === "boolean" && item.type !== 'checkbox'){ //boolean means visibility, except checkbox
  40. if (value){
  41. item.style.display = "originalDisplay" in item ? item.originalDisplay : "";
  42. }
  43. else {
  44. item.originalDisplay = item.style.display;
  45. item.style.display = "none";
  46. }
  47. return;
  48. }
  49. if (item.type === 'radio' && !keyExists){ //radiogroup set
  50. if (item.value === value){ //only item with right value to set
  51. item.checked = true;
  52. }
  53. return;
  54. }
  55. if (item.type === 'checkbox' && !keyExists){ //checkbox setting by boolean
  56. item.checked = !!value;
  57. return;
  58. }
  59. if (item.children.length && typeof value === "object"){ //recursive fill
  60. item.copy = item.copy || item.cloneNode(true); //original node
  61. var originalChildren = item.copy.children;
  62. var i = 0;
  63. var isArray = Array.isArray(value); //different logic for array and objects
  64. if (!isArray){ // if first key in array find as class name in one of subnodes
  65. var classFound = false;
  66. for (var key in value){
  67. if (item.getElementsByClassName(key).length){
  68. classFound = true;
  69. break;
  70. }
  71. }
  72. if (classFound){
  73. for (var key in value){
  74. var classSubnodes = item.getElementsByClassName(key);
  75. for (var i=0;i<classSubnodes.length;i++){
  76. arguments.callee(classSubnodes[i], $s, selector, value[key]); // recursively fill subnode with that data. No reason to pass a key, because key are class selector, not value for option
  77. }
  78. }
  79. return;
  80. }
  81. }
  82. item.innerHTML = ""; //remove sub nodes
  83. for (var key in value){ //otherwise iterate over array or object
  84. var newNode = originalChildren[i].cloneNode(true);
  85. item.appendChild(newNode);
  86. if (isArray){
  87. arguments.callee(newNode, $s, selector, value[key]);
  88. }
  89. else {
  90. arguments.callee(newNode, $s, selector, value[key], key);
  91. }
  92. i = (i +1) % originalChildren.length;
  93. }
  94. return;
  95. }
  96. if (!keyExists){ //default logic: set text or value to data value
  97. item["value" in item ? "value" : "innerText"] = value;
  98. }
  99. else {
  100. item.innerText = value; // do not try to overwrite value on option nodes
  101. }
  102. },prop, "write");
  103. }
  104. function syncFromDOM(prop){
  105. nBind(function(item, $s, selector){
  106. if (item.type === 'radio'){
  107. if (item.checked)
  108. return item.value;
  109. return;
  110. }
  111. if (item.type === 'checkbox'){
  112. return item.checked;
  113. }
  114. return item["value" in item ? "value" : "innerText"];
  115. },prop, "read");
  116. }
  117. syncToDOM();
  118. var scopeProxy = new Proxy($s,{
  119. get(target, prop){
  120. if (!(prop in target) && (document.getElementById(prop) ||
  121. document.querySelectorAll(prop).length ||
  122. document.getElementsByName(prop).length ||
  123. document.getElementsByClassName(prop).length)){
  124. target[prop] = null;
  125. }
  126. syncFromDOM(prop);
  127. return target[prop];
  128. },
  129. set(target, prop, value){
  130. //syncFromDOM();
  131. target[prop] = value
  132. syncToDOM(prop);
  133. return true;
  134. },
  135. })
  136. return scopeProxy;
  137. }
  138. var $s;
  139. setTimeout(function(){
  140. $s = nbInit({
  141. text1: "txt",
  142. p1: "para",
  143. select: {"": "--",
  144. M: "Male",
  145. F: "Female",
  146. X: "Xenomorph"},
  147. numberTable: [[1,2,3,4,5,6],
  148. [7,8,9,10,11,12],
  149. [13,14,15,16,17,18],
  150. /*[19,20,21,22,23,24]*/],
  151. //numberTable: [[[{"": "--",
  152. //M: "Male",
  153. //F: "Female",
  154. //X: "Xenomorph"}],
  155. //[{"": "--",
  156. //M: "Male",
  157. //F: "Female",
  158. //X: "Xenomorph"}],
  159. //[{"": "--",
  160. //M: "Male",
  161. //F: "Female",
  162. //X: "Xenomorph"}]],
  163. //[[{"": "--",
  164. //M: "Male",
  165. //F: "Female",
  166. //X: "Xenomorph"}],
  167. //[{"": "--",
  168. //M: "Male",
  169. //F: "Female",
  170. //X: "Xenomorph"}],
  171. //[{"": "--",
  172. //M: "Male",
  173. //F: "Female",
  174. //X: "Xenomorph"}]]],
  175. hashTable: [{ name: "Ivan",
  176. surname: "Ivanovv",
  177. age: "57",
  178. note: {innerText: "Buhaet", name: 'ivanovvsTextArea'},
  179. married: true},
  180. { name: "Petr",
  181. surname: "Petroff",
  182. age: "17",
  183. note: "Tyolki v golove",
  184. married: false,
  185. },
  186. { name: "Mary",
  187. surname: "Tester",
  188. married: true,
  189. note: "Ovulyashka",
  190. age: "27"} ],
  191. checks: [
  192. {check: {name: "first", checked: true},
  193. description: "first check"},
  194. {check: {name: "second", checked: false},
  195. description: "second check"},
  196. {check: {name: "third", checked: true},
  197. description: "third check"},
  198. ],
  199. radios: [
  200. {radio: {name: "sexism", value: "M", checked: true},
  201. description: "Male"},
  202. {radio: {name: "sexism", value: "F"},
  203. description: "Female"},
  204. {radio: {name: "racism", value: "white", checked: true},
  205. description: "White"},
  206. {radio: {name: "racism", value: "black"},
  207. description: "Black"}, ]
  208. });
  209. $s.textarea; $s.select; $s.dzen; $s.check1; $s.note; $s.married; //just for init
  210. document.onchange();
  211. },2000);
  212. document.onchange = function(){
  213. $s.state = "";
  214. $s.state = JSON.stringify($s, null, 4);
  215. }