index.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. function nbInit($s){
  2. function nBind(callback, prop){
  3. for (var selector in $s){
  4. selector = prop || selector; //change selector to passed if it
  5. var items = document.querySelectorAll(selector);
  6. items = items.length ? items : [document.getElementById(selector)];
  7. items = items[0] ? items : document.getElementsByName(selector);
  8. for (var i=0,item=items[i];i<items.length;i++,item=items[i]){
  9. callback(item, $s, selector)
  10. }
  11. if (prop) return; //exit if selector passed, no iteration
  12. }
  13. }
  14. function syncToDOM(prop){
  15. nBind(function (item, $s, selector, value, key){
  16. value = typeof value === 'undefined' ? $s[selector] : value;
  17. var keyExists = typeof key !== 'undefined';
  18. if (keyExists && "value" in item){ //if hash key-value pair. Usable for select > option
  19. item.value = key;
  20. }
  21. if (typeof value === "boolean" && item.type !== 'checkbox'){ //boolean means visibility, except checkbox
  22. if (value){
  23. item.style.display = "originalDisplay" in item ? item.originalDisplay : "";
  24. }
  25. else {
  26. item.originalDisplay = item.style.display;
  27. item.style.display = "none";
  28. }
  29. return;
  30. }
  31. if (item.type === 'radio' && !keyExists){ //radiogroup set
  32. if (item.value === value){ //only item with right value to set
  33. item.checked = true;
  34. }
  35. return;
  36. }
  37. if (item.type === 'checkbox' && !keyExists){ //checkbox setting by boolean
  38. item.checked = !!value;
  39. return;
  40. }
  41. if (item.children.length && typeof value === "object"){ //recursive fill
  42. item.copy = item.copy || item.cloneNode(true); //original node
  43. var originalChildren = item.copy.children;
  44. var i = 0;
  45. var isArray = Array.isArray(value); //different logic for array and objects
  46. if (!isArray){ // if first key in array find as class name in one of subnodes
  47. var classFound = false;
  48. for (var key in value){
  49. if (item.getElementsByClassName(key).length){
  50. classFound = true;
  51. break;
  52. }
  53. }
  54. if (classFound){
  55. for (var key in value){
  56. var classSubnodes = item.getElementsByClassName(key);
  57. for (var i=0;i<classSubnodes.length;i++){
  58. 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
  59. }
  60. }
  61. return;
  62. }
  63. }
  64. item.innerHTML = ""; //remove sub nodes
  65. for (var key in value){ //otherwise iterate over array or object
  66. var newNode = originalChildren[i].cloneNode(true);
  67. item.appendChild(newNode);
  68. if (isArray){
  69. arguments.callee(newNode, $s, selector, value[key]);
  70. }
  71. else {
  72. arguments.callee(newNode, $s, selector, value[key], key);
  73. }
  74. i = (i +1) % originalChildren.length;
  75. }
  76. return;
  77. }
  78. if (!keyExists){ //default logic: set text or value to data value
  79. item["value" in item ? "value" : "innerText"] = value;
  80. }
  81. else {
  82. item.innerText = value; // do not try to overwrite value on option nodes
  83. }
  84. },prop);
  85. }
  86. function syncFromDOM(){
  87. nBind(function(item, $s, selector){
  88. if (item.type === 'radio'){
  89. if (item.checked)
  90. $s[selector] = item.value;
  91. return;
  92. }
  93. if (item.type === 'checkbox'){
  94. $s[selector] = item.checked;
  95. return;
  96. }
  97. $s[selector] = item["value" in item ? "value" : "innerText"];
  98. });
  99. }
  100. syncToDOM();
  101. var scopeProxy = new Proxy($s,{
  102. get(target, prop){
  103. if (!(prop in target) && (document.querySelectorAll(prop).length || document.getElementById(prop) || document.getElementsByName(prop).length)){
  104. target[prop] = null;
  105. }
  106. syncFromDOM();
  107. return target[prop];
  108. },
  109. set(target, prop, value){
  110. //syncFromDOM();
  111. target[prop] = value
  112. syncToDOM(prop);
  113. return true;
  114. },
  115. })
  116. return scopeProxy;
  117. }
  118. var $s;
  119. setTimeout(function(){
  120. $s = nbInit({
  121. text1: "txt",
  122. p1: "para",
  123. select: {"": "--",
  124. M: "Male",
  125. F: "Female",
  126. X: "Xenomorph"},
  127. numberTable: [[1,2,3,4,5,6],
  128. [7,8,9,10,11,12],
  129. [13,14,15,16,17,18],
  130. /*[19,20,21,22,23,24]*/],
  131. hashTable: [{ name: "Ivan",
  132. surname: "Ivanovv",
  133. age: "57"},
  134. { name: "Petr",
  135. surname: "Petroff",
  136. age: "17"},
  137. { name: "Mary",
  138. surname: "Tester",
  139. age: "27"} ]});
  140. $s.textarea; $s.select; $s.dzen; $s.check1; //just for init
  141. document.onchange();
  142. },2000);
  143. document.onchange = function(){
  144. $s.state = "";
  145. $s.state = JSON.stringify($s, null, 4);
  146. }