dq.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. (function() {
  2. window.initDQ = function() {
  3. $(document)
  4. .off('change input paste', '.dq-edit-container input, .dq-edit-container textarea, .dq-edit-container select')
  5. .on('change input paste', '.dq-edit-container input, .dq-edit-container textarea, .dq-edit-container select', function() {
  6. let key = $(this).closest('.dq-line').attr('dq-key'),
  7. dataElem = $(this).closest('.dq-edit-container').find('>.dq-data-map').first(),
  8. current = JSON.parse(dataElem.text());
  9. current[key] = $(this).val();
  10. let serialized = JSON.stringify(current);
  11. dataElem.text(serialized);
  12. $(this).closest('form').find('input[name="data"]').val(serialized);
  13. let fullData = {
  14. lines: JSON.parse($(this).closest('.dq-edit-container').find('>.dq-definition').first().text()),
  15. dataMap: current
  16. };
  17. $(this).closest('form').find('input[name="data"]').val(JSON.stringify(fullData));
  18. runDQConditions($(this).closest('.dq-edit-container'));
  19. });
  20. $(document)
  21. .off('input.auto-grow', '.dq-edit-container textarea')
  22. .on('input.auto-grow', '.dq-edit-container textarea', function() {
  23. this.style.minHeight = "calc(1.5em + .5rem + 2px)";
  24. this.style.height = "calc(1.5em + .5rem + 2px)";
  25. this.style.height = (this.scrollHeight)+"px";
  26. });
  27. };
  28. function resolveAtomicCondition(_condition, _dataMap) {
  29. if(!_condition.hasOwnProperty('key') || !_condition.hasOwnProperty('value')) {
  30. _condition.resolution = false;
  31. return;
  32. }
  33. let key = _condition.key, op = _condition.hasOwnProperty('op') ? _condition.op : 'eq';
  34. let lhs = _dataMap[key], rhs = _condition.value;
  35. switch(op) {
  36. case 'eq':
  37. _condition.resolution = (lhs == rhs); // NOTE: using == instead of === on purpose
  38. break;
  39. case 'lt':
  40. _condition.resolution = (+lhs < +rhs);
  41. break;
  42. case 'lte':
  43. _condition.resolution = (+lhs <= +rhs);
  44. break;
  45. case 'gt':
  46. _condition.resolution = (+lhs > +rhs);
  47. break;
  48. case 'gte':
  49. _condition.resolution = (+lhs >= +rhs);
  50. break;
  51. default:
  52. _condition.resolution = false;
  53. }
  54. }
  55. function resolveAllAtomicConditions(_conditions, _dataMap) {
  56. if(Array.isArray(_conditions)) {
  57. for (let i = 0; i < _conditions.length; i++) {
  58. resolveAllAtomicConditions(_conditions[i], _dataMap);
  59. }
  60. }
  61. else if(typeof _conditions === 'object') {
  62. resolveAtomicCondition(_conditions, _dataMap);
  63. }
  64. }
  65. function reduceConditionsIntoResolutions(_conditions) {
  66. for (let i = 0; i < _conditions.length; i++) {
  67. // if simple object, resolve
  68. if(!Array.isArray(_conditions[i]) && typeof _conditions[i] === 'object') {
  69. _conditions.splice(i, 1, _conditions[i].resolution);
  70. }
  71. else if(Array.isArray(_conditions[i])) {
  72. reduceConditionsIntoResolutions(_conditions[i]);
  73. }
  74. }
  75. }
  76. function combineResolutionListsIntoSingleResolutions(_conditions) {
  77. console.log('ALIX 1', _conditions);
  78. for (let i = 0; i < _conditions.length; i++) {
  79. if(Array.isArray(_conditions[i])) {
  80. _conditions[i] = combineResolutionListsIntoSingleResolutions(_conditions[i]);
  81. }
  82. }
  83. console.log('ALIX 2', _conditions);
  84. // at this point, the array will have only booleans and "AND", "OR" combinators
  85. let resolution = _conditions[0];
  86. for (let i = 1; i < _conditions.length; i+=2) {
  87. if(_conditions[i] === 'AND') {
  88. resolution = resolution && _conditions[i + 1];
  89. }
  90. else if(_conditions[i] === 'OR') {
  91. resolution = resolution || _conditions[i + 1];
  92. }
  93. }
  94. return resolution;
  95. }
  96. window.runDQConditions = function(_parent) {
  97. _parent.find('.dq-line.has-pre-condition').each(function() {
  98. let conditions = JSON.parse($(this).find('>.dq-pre-condition').first().text()),
  99. dataMap = JSON.parse($(this).closest('.dq-edit-container').find('>.dq-data-map').first().text());
  100. resolveAllAtomicConditions(conditions, dataMap);
  101. // if object, single condition with key, op and value
  102. if(!Array.isArray(conditions) && typeof conditions === 'object') {
  103. if(conditions.resolution) {
  104. $(this).removeClass('d-none');
  105. }
  106. else {
  107. $(this).addClass('d-none');
  108. }
  109. }
  110. // else if array - means list of conditions with 'and' or 'or' separators - array size MUST be an odd number
  111. else if(Array.isArray(conditions)) {
  112. // goal is to reduce each item in the array into a single boolean - recursively
  113. reduceConditionsIntoResolutions(conditions);
  114. conditions = combineResolutionListsIntoSingleResolutions(conditions);
  115. if(conditions) {
  116. $(this).removeClass('d-none');
  117. }
  118. else {
  119. $(this).addClass('d-none');
  120. }
  121. }
  122. });
  123. }
  124. addMCInitializer('dq-edit', initDQ, '.dq-edit-container');
  125. }).call(window);