diff --git a/assets/css/code-mirror/show-hint.min.css b/assets/css/code-mirror/show-hint.min.css new file mode 100644 index 000000000..311e1c392 --- /dev/null +++ b/assets/css/code-mirror/show-hint.min.css @@ -0,0 +1 @@ +.CodeMirror-hints{position:absolute;z-index:10;overflow:hidden;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px rgba(0,0,0,.2);border-radius:3px;border:1px solid silver;background:#fff;font-size:90%;font-family:monospace;max-height:20em;overflow-y:auto}.CodeMirror-hint{margin:0;padding:0 4px;border-radius:2px;white-space:pre;color:#000;cursor:pointer}li.CodeMirror-hint-active{background:#08f;color:#fff} \ No newline at end of file diff --git a/assets/extensions-json/sections/all_extensions.json b/assets/extensions-json/sections/all_extensions.json index cecb58984..2fcf11dc3 100644 --- a/assets/extensions-json/sections/all_extensions.json +++ b/assets/extensions-json/sections/all_extensions.json @@ -254,23 +254,6 @@ "demo_video_url": "Q1-dja7m3Sc", "popular_rank": 15 }, - { - "title": "Calculations", - "slug": "everest-forms-calculations", - "name": "Everest Forms Calculations", - "image": "extensions-json/sections/images/calculations.png", - "excerpt": "Calculations add-on allows you to perform calculations on the number/range fields within the form.", - "link": "https://docs.everestforms.net/docs/calculations/?utm_source=dashboard-all-feature&utm_medium=card-documentation-link", - "released_date": "29/03/2022", - "plan": [ - "personal", - "agency", - "themegrill agency" - ], - "setting_url": "", - "demo_video_url": "WCsHC7NQ2QQ", - "popular_rank": 16 - }, { "title": "Post Submissions", "slug": "everest-forms-post-submissions", @@ -869,6 +852,23 @@ ], "setting_url": "admin.php?page=evf-settings&tab=integration§ion=aweber", "demo_video_url": "" + }, + { + "title": "Calculations", + "slug": "everest-forms-calculations", + "name": "Everest Forms Calculations", + "image": "extensions-json/sections/images/calculations.png", + "excerpt": "Calculations add-on allows you to perform calculations on the number/range fields within the form.", + "link": "https://docs.everestforms.net/docs/calculations/?utm_source=dashboard-all-feature&utm_medium=card-documentation-link", + "released_date": "29/03/2022", + "plan": [ + "personal", + "agency", + "themegrill agency" + ], + "setting_url": "", + "demo_video_url": "WCsHC7NQ2QQ", + "popular_rank": 16 } ] } diff --git a/assets/js/admin/form-builder.js b/assets/js/admin/form-builder.js index 665003fb3..149bc831b 100644 --- a/assets/js/admin/form-builder.js +++ b/assets/js/admin/form-builder.js @@ -3618,12 +3618,19 @@ jQuery( function ( $ ) { $( document.body ).on('click', '.smart-tag-field', function(e) { - var field_id = $( this ).data('field_id'), - field_label = $( this ).text(), - type = $( this ).data('type'), - $parent = $ ( this ).parent().parent().parent(), - $input = $parent.find('input[type=text]'), - $textarea = $parent.find('textarea'); + var field_id = $( this ).data('field_id'), + field_label = $( this ).text(), + type = $( this ).data('type'), + $parent = $ ( this ).parent().parent().parent(), + $input = $parent.find('input[type=text]'), + $textarea = $parent.find('textarea'), + $calculationCodeMirror = $parent.find( '.CodeMirror'); + + //Return when calculation smart tag is clicked because we use codeMirror + if( 0 != $calculationCodeMirror.length ){ + return; + } + if ( field_id !== 'fullname' && field_id !== 'email' && field_id !== 'subject' && field_id !== 'message' && 'other' !== type ) { field_label = field_label.split(/[\s-_]/); for(var i = 0 ; i < field_label.length ; i++){ @@ -3879,10 +3886,19 @@ jQuery( function ( $ ) { "range-slider", "payment-checkbox", "payment-multiple", + "select", + "payment-total", + "radio", + 'first-name', + 'text', + 'last-name', + 'email', + 'url' ]; $(document).find('.everest-forms-field').each(function() { + $fieldId = $(this).attr('data-field-id').split("-"); if( calculations.includes($(this).attr('data-field-type')) && $(el).parents('.everest-forms-field-option-row-calculation_field').attr('data-field-id') !== $(this).attr('data-field-id')) { - $(el).parent().find('.evf-smart-tag-lists .calculations').append('
  • '+$(this).find('.label-title .text').text()+'
  • '); + $(el).parent().find('.evf-smart-tag-lists .calculations').append('
  • '+$(this).find('.label-title .text').text()+'
  • '); } }) } diff --git a/assets/js/code-mirror/show-hint.js b/assets/js/code-mirror/show-hint.js new file mode 100644 index 000000000..84e0824e1 --- /dev/null +++ b/assets/js/code-mirror/show-hint.js @@ -0,0 +1,405 @@ +!(function (t) { + "object" == typeof exports && "object" == typeof module ? t(require("../../lib/codemirror")) : "function" == typeof define && define.amd ? define(["../../lib/codemirror"], t) : t(CodeMirror); +})(function (T) { + "use strict"; + var F = "CodeMirror-hint-active"; + function n(t, e) { + var i; + (this.cm = t), + (this.options = e), + (this.widget = null), + (this.debounce = 0), + (this.tick = 0), + (this.startPos = this.cm.getCursor("start")), + (this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length), + this.options.updateOnCursorActivity && + t.on( + "cursorActivity", + ((i = this).activityFunc = function () { + i.cursorActivity(); + }) + ); + } + (T.showHint = function (t, e, i) { + if (!e) return t.showHint(i); + i && i.async && (e.async = !0); + var n = { hint: e }; + if (i) for (var o in i) n[o] = i[o]; + return t.showHint(n); + }), + T.defineExtension("showHint", function (t) { + t = (function (t, e, i) { + var n = t.options.hintOptions, + o = {}; + for (s in c) o[s] = c[s]; + if (n) for (var s in n) void 0 !== n[s] && (o[s] = n[s]); + if (i) for (var s in i) void 0 !== i[s] && (o[s] = i[s]); + o.hint.resolve && (o.hint = o.hint.resolve(t, e)); + return o; + })(this, this.getCursor("start"), t); + var e = this.listSelections(); + if (!(1 < e.length)) { + if (this.somethingSelected()) { + if (!t.hint.supportsSelection) return; + for (var i = 0; i < e.length; i++) if (e[i].head.line != e[i].anchor.line) return; + } + this.state.completionActive && this.state.completionActive.close(); + t = this.state.completionActive = new n(this, t); + t.options.hint && (T.signal(this, "startCompletion", this), t.update(!0)); + } + }), + T.defineExtension("closeHint", function () { + this.state.completionActive && this.state.completionActive.close(); + }); + var o = + window.requestAnimationFrame || + function (t) { + return setTimeout(t, 1e3 / 60); + }, + s = window.cancelAnimationFrame || clearTimeout; + function M(t) { + return "string" == typeof t ? t : t.text; + } + function O(t, e) { + for (; e && e != t; ) { + if ("LI" === e.nodeName.toUpperCase() && e.parentNode == t) return e; + e = e.parentNode; + } + } + function i(o, t) { + (this.id = "cm-complete-" + Math.floor(Math.random(1e6))), (this.completion = o), (this.data = t), (this.picked = !1); + var i = this, + s = o.cm, + c = s.getInputField().ownerDocument, + r = c.defaultView || c.parentWindow, + l = (this.hints = c.createElement("ul")); + l.setAttribute("role", "listbox"), l.setAttribute("aria-expanded", "true"), (l.id = this.id); + var e = o.cm.options.theme; + (l.className = "CodeMirror-hints " + e), (this.selectedHint = t.selectedHint || 0); + for (var n = t.list, h = 0; h < n.length; ++h) { + var a = l.appendChild(c.createElement("li")), + u = n[h], + d = "CodeMirror-hint" + (h != this.selectedHint ? "" : " " + F); + null != u.className && (d = u.className + " " + d), + (a.className = d), + h == this.selectedHint && a.setAttribute("aria-selected", "true"), + (a.id = this.id + "-" + h), + a.setAttribute("role", "option"), + u.render ? u.render(a, t, u) : a.appendChild(c.createTextNode(u.displayText || M(u))), + (a.hintId = h); + } + var f = o.options.container || c.body, + p = s.cursorCoords(o.options.alignWithWord ? t.from : null), + m = p.left, + g = p.bottom, + v = !0, + y = 0, + b = 0; + f !== c.body && + ((w = (C = -1 !== ["absolute", "relative", "fixed"].indexOf(r.getComputedStyle(f).position) ? f : f.offsetParent).getBoundingClientRect()), + (H = c.body.getBoundingClientRect()), + (y = w.left - H.left - C.scrollLeft), + (b = w.top - H.top - C.scrollTop)), + (l.style.left = m - y + "px"), + (l.style.top = g - b + "px"); + var e = r.innerWidth || Math.max(c.body.offsetWidth, c.documentElement.offsetWidth), + w = r.innerHeight || Math.max(c.body.offsetHeight, c.documentElement.offsetHeight); + f.appendChild(l), s.getInputField().setAttribute("aria-autocomplete", "list"), s.getInputField().setAttribute("aria-owns", this.id), s.getInputField().setAttribute("aria-activedescendant", this.id + "-" + this.selectedHint); + var A, + H = o.options.moveOnOverlap ? l.getBoundingClientRect() : new DOMRect(), + C = !!o.options.paddingForScrollbar && l.scrollHeight > l.clientHeight + 1; + setTimeout(function () { + A = s.getScrollInfo(); + }), + 0 < H.bottom - w && + ((f = H.bottom - H.top), + 0 < p.top - (p.bottom - H.top) - f + ? ((l.style.top = (g = p.top - f - b) + "px"), (v = !1)) + : w < f && + ((l.style.height = w - 5 + "px"), + (l.style.top = (g = p.bottom - H.top - b) + "px"), + (x = s.getCursor()), + t.from.ch != x.ch && ((p = s.cursorCoords(x)), (l.style.left = (m = p.left - y) + "px"), (H = l.getBoundingClientRect())))); + var k, + x = H.right - e; + if ((C && (x += s.display.nativeBarWidth), 0 < x && (H.right - H.left > e && ((l.style.width = e - 5 + "px"), (x -= H.right - H.left - e)), (l.style.left = (m = p.left - x - y) + "px")), C)) + for (var S = l.firstChild; S; S = S.nextSibling) S.style.paddingRight = s.display.nativeBarWidth + "px"; + s.addKeyMap( + (this.keyMap = (function (t, n) { + var o = { + Up: function () { + n.moveFocus(-1); + }, + Down: function () { + n.moveFocus(1); + }, + PageUp: function () { + n.moveFocus(1 - n.menuSize(), !0); + }, + PageDown: function () { + n.moveFocus(n.menuSize() - 1, !0); + }, + Home: function () { + n.setFocus(0); + }, + End: function () { + n.setFocus(n.length - 1); + }, + Enter: n.pick, + Tab: n.pick, + Esc: n.close, + }; + /Mac/.test(navigator.platform) && + ((o["Ctrl-P"] = function () { + n.moveFocus(-1); + }), + (o["Ctrl-N"] = function () { + n.moveFocus(1); + })); + var e = t.options.customKeys, + s = e ? {} : o; + function i(t, e) { + var i = + "string" != typeof e + ? function (t) { + return e(t, n); + } + : o.hasOwnProperty(e) + ? o[e] + : e; + s[t] = i; + } + if (e) for (var c in e) e.hasOwnProperty(c) && i(c, e[c]); + var r = t.options.extraKeys; + if (r) for (var c in r) r.hasOwnProperty(c) && i(c, r[c]); + return s; + })(o, { + moveFocus: function (t, e) { + i.changeActive(i.selectedHint + t, e); + }, + setFocus: function (t) { + i.changeActive(t); + }, + menuSize: function () { + return i.screenAmount(); + }, + length: n.length, + close: function () { + o.close(); + }, + pick: function () { + i.pick(); + }, + data: t, + })) + ), + o.options.closeOnUnfocus && + (s.on( + "blur", + (this.onBlur = function () { + k = setTimeout(function () { + o.close(); + }, 100); + }) + ), + s.on( + "focus", + (this.onFocus = function () { + clearTimeout(k); + }) + )), + s.on( + "scroll", + (this.onScroll = function () { + var t = s.getScrollInfo(), + e = s.getWrapperElement().getBoundingClientRect(); + A = A || s.getScrollInfo(); + var i = g + A.top - t.top, + n = i - (r.pageYOffset || (c.documentElement || c.body).scrollTop); + if ((v || (n += l.offsetHeight), n <= e.top || n >= e.bottom)) return o.close(); + (l.style.top = i + "px"), (l.style.left = m + A.left - t.left + "px"); + }) + ), + T.on(l, "dblclick", function (t) { + t = O(l, t.target || t.srcElement); + t && null != t.hintId && (i.changeActive(t.hintId), i.pick()); + }), + T.on(l, "click", function (t) { + t = O(l, t.target || t.srcElement); + t && null != t.hintId && (i.changeActive(t.hintId), o.options.completeOnSingleClick && i.pick()); + }), + T.on(l, "mousedown", function () { + setTimeout(function () { + s.focus(); + }, 20); + }); + C = this.getSelectedHintRange(); + return (0 === C.from && 0 === C.to) || this.scrollToActive(), T.signal(t, "select", n[this.selectedHint], l.childNodes[this.selectedHint]), !0; + } + function r(t, e, i, n) { + t.async ? t(e, n, i) : (i = t(e, i)) && i.then ? i.then(n) : n(i); + } + (n.prototype = { + close: function () { + this.active() && + ((this.cm.state.completionActive = null), + (this.tick = null), + this.options.updateOnCursorActivity && this.cm.off("cursorActivity", this.activityFunc), + this.widget && this.data && T.signal(this.data, "close"), + this.widget && this.widget.close(), + T.signal(this.cm, "endCompletion", this.cm)); + }, + active: function () { + return this.cm.state.completionActive == this; + }, + pick: function (t, e) { + var i = t.list[e], + n = this; + this.cm.operation(function () { + i.hint ? i.hint(n.cm, t, i) : n.cm.replaceRange(M(i), i.from || t.from, i.to || t.to, "complete"), T.signal(t, "pick", i), n.cm.scrollIntoView(); + }), + this.options.closeOnPick && this.close(); + }, + cursorActivity: function () { + this.debounce && (s(this.debounce), (this.debounce = 0)); + var t = this.startPos; + this.data && (t = this.data.from); + var e, + i = this.cm.getCursor(), + n = this.cm.getLine(i.line); + i.line != this.startPos.line || n.length - i.ch != this.startLen - this.startPos.ch || i.ch < t.ch || this.cm.somethingSelected() || !i.ch || this.options.closeCharacters.test(n.charAt(i.ch - 1)) + ? this.close() + : (((e = this).debounce = o(function () { + e.update(); + })), + this.widget && this.widget.disable()); + }, + update: function (e) { + var i, n; + null != this.tick && + ((n = ++(i = this).tick), + r(this.options.hint, this.cm, this.options, function (t) { + i.tick == n && i.finishUpdate(t, e); + })); + }, + finishUpdate: function (t, e) { + this.data && T.signal(this.data, "update"); + e = (this.widget && this.widget.picked) || (e && this.options.completeSingle); + this.widget && this.widget.close(), (this.data = t) && t.list.length && (e && 1 == t.list.length ? this.pick(t, 0) : ((this.widget = new i(this, t)), T.signal(t, "shown"))); + }, + }), + (i.prototype = { + close: function () { + var t; + this.completion.widget == this && + ((this.completion.widget = null), + this.hints.parentNode && this.hints.parentNode.removeChild(this.hints), + this.completion.cm.removeKeyMap(this.keyMap), + (t = this.completion.cm.getInputField()).removeAttribute("aria-activedescendant"), + t.removeAttribute("aria-owns"), + (t = this.completion.cm), + this.completion.options.closeOnUnfocus && (t.off("blur", this.onBlur), t.off("focus", this.onFocus)), + t.off("scroll", this.onScroll)); + }, + disable: function () { + this.completion.cm.removeKeyMap(this.keyMap); + var t = this; + (this.keyMap = { + Enter: function () { + t.picked = !0; + }, + }), + this.completion.cm.addKeyMap(this.keyMap); + }, + pick: function () { + this.completion.pick(this.data, this.selectedHint); + }, + changeActive: function (t, e) { + t >= this.data.list.length ? (t = e ? this.data.list.length - 1 : 0) : t < 0 && (t = e ? 0 : this.data.list.length - 1), + this.selectedHint != t && + ((e = this.hints.childNodes[this.selectedHint]) && ((e.className = e.className.replace(" " + F, "")), e.removeAttribute("aria-selected")), + ((e = this.hints.childNodes[(this.selectedHint = t)]).className += " " + F), + e.setAttribute("aria-selected", "true"), + this.completion.cm.getInputField().setAttribute("aria-activedescendant", e.id), + this.scrollToActive(), + T.signal(this.data, "select", this.data.list[this.selectedHint], e)); + }, + scrollToActive: function () { + var t = this.getSelectedHintRange(), + e = this.hints.childNodes[t.from], + i = this.hints.childNodes[t.to], + t = this.hints.firstChild; + e.offsetTop < this.hints.scrollTop + ? (this.hints.scrollTop = e.offsetTop - t.offsetTop) + : i.offsetTop + i.offsetHeight > this.hints.scrollTop + this.hints.clientHeight && (this.hints.scrollTop = i.offsetTop + i.offsetHeight - this.hints.clientHeight + t.offsetTop); + }, + screenAmount: function () { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + }, + getSelectedHintRange: function () { + var t = this.completion.options.scrollMargin || 0; + return { from: Math.max(0, this.selectedHint - t), to: Math.min(this.data.list.length - 1, this.selectedHint + t) }; + }, + }), + T.registerHelper("hint", "auto", { + resolve: function (t, e) { + var i, + c = t.getHelpers(e, "hint"); + if (c.length) { + e = function (t, n, o) { + var s = (function (t, e) { + if (!t.somethingSelected()) return e; + for (var i = [], n = 0; n < e.length; n++) e[n].supportsSelection && i.push(e[n]); + return i; + })(t, c); + !(function e(i) { + if (i == s.length) return n(null); + r(s[i], t, o, function (t) { + t && 0 < t.list.length ? n(t) : e(i + 1); + }); + })(0); + }; + return (e.async = !0), (e.supportsSelection = !0), e; + } + return (i = t.getHelper(t.getCursor(), "hintWords")) + ? function (t) { + return T.hint.fromList(t, { words: i }); + } + : T.hint.anyword + ? function (t, e) { + return T.hint.anyword(t, e); + } + : function () {}; + }, + }), + T.registerHelper("hint", "fromList", function (t, e) { + var i, + n = t.getCursor(), + o = t.getTokenAt(n), + s = T.Pos(n.line, o.start), + t = n; + o.start < n.ch && /\w/.test(o.string.charAt(n.ch - o.start - 1)) ? (i = o.string.substr(0, n.ch - o.start)) : ((i = ""), (s = n)); + for (var c = [], r = 0; r < e.words.length; r++) { + var l = e.words[r]; + l.slice(0, i.length) == i && c.push(l); + } + if (c.length) return { list: c, from: s, to: t }; + }), + (T.commands.autocomplete = T.showHint); + var c = { + hint: T.hint.auto, + completeSingle: !0, + alignWithWord: !0, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnPick: !0, + closeOnUnfocus: !0, + updateOnCursorActivity: !0, + completeOnSingleClick: !0, + container: null, + customKeys: null, + extraKeys: null, + paddingForScrollbar: !0, + moveOnOverlap: !0, + }; + T.defineOption("hintOptions", null); +}); diff --git a/assets/js/code-mirror/show-hint.min.js b/assets/js/code-mirror/show-hint.min.js new file mode 100644 index 000000000..0f645c42a --- /dev/null +++ b/assets/js/code-mirror/show-hint.min.js @@ -0,0 +1 @@ +!function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(T){"use strict";var F="CodeMirror-hint-active";function n(t,e){var i;this.cm=t,this.options=e,this.widget=null,this.debounce=0,this.tick=0,this.startPos=this.cm.getCursor("start"),this.startLen=this.cm.getLine(this.startPos.line).length-this.cm.getSelection().length,this.options.updateOnCursorActivity&&t.on("cursorActivity",(i=this).activityFunc=function(){i.cursorActivity()})}T.showHint=function(t,e,i){if(!e)return t.showHint(i);i&&i.async&&(e.async=!0);var n={hint:e};if(i)for(var o in i)n[o]=i[o];return t.showHint(n)},T.defineExtension("showHint",function(t){t=function(t,e,i){var n=t.options.hintOptions,o={};for(s in c)o[s]=c[s];if(n)for(var s in n)void 0!==n[s]&&(o[s]=n[s]);if(i)for(var s in i)void 0!==i[s]&&(o[s]=i[s]);o.hint.resolve&&(o.hint=o.hint.resolve(t,e));return o}(this,this.getCursor("start"),t);var e=this.listSelections();if(!(1l.clientHeight+1;setTimeout(function(){A=s.getScrollInfo()}),0e&&(l.style.width=e-5+"px",x-=H.right-H.left-e),l.style.left=(m=p.left-x-y)+"px"),C)for(var S=l.firstChild;S;S=S.nextSibling)S.style.paddingRight=s.display.nativeBarWidth+"px";s.addKeyMap(this.keyMap=function(t,n){var o={Up:function(){n.moveFocus(-1)},Down:function(){n.moveFocus(1)},PageUp:function(){n.moveFocus(1-n.menuSize(),!0)},PageDown:function(){n.moveFocus(n.menuSize()-1,!0)},Home:function(){n.setFocus(0)},End:function(){n.setFocus(n.length-1)},Enter:n.pick,Tab:n.pick,Esc:n.close};/Mac/.test(navigator.platform)&&(o["Ctrl-P"]=function(){n.moveFocus(-1)},o["Ctrl-N"]=function(){n.moveFocus(1)});var e=t.options.customKeys,s=e?{}:o;function i(t,e){var i="string"!=typeof e?function(t){return e(t,n)}:o.hasOwnProperty(e)?o[e]:e;s[t]=i}if(e)for(var c in e)e.hasOwnProperty(c)&&i(c,e[c]);var r=t.options.extraKeys;if(r)for(var c in r)r.hasOwnProperty(c)&&i(c,r[c]);return s}(o,{moveFocus:function(t,e){i.changeActive(i.selectedHint+t,e)},setFocus:function(t){i.changeActive(t)},menuSize:function(){return i.screenAmount()},length:n.length,close:function(){o.close()},pick:function(){i.pick()},data:t})),o.options.closeOnUnfocus&&(s.on("blur",this.onBlur=function(){k=setTimeout(function(){o.close()},100)}),s.on("focus",this.onFocus=function(){clearTimeout(k)})),s.on("scroll",this.onScroll=function(){var t=s.getScrollInfo(),e=s.getWrapperElement().getBoundingClientRect();A=A||s.getScrollInfo();var i=g+A.top-t.top,n=i-(r.pageYOffset||(c.documentElement||c.body).scrollTop);if(v||(n+=l.offsetHeight),n<=e.top||n>=e.bottom)return o.close();l.style.top=i+"px",l.style.left=m+A.left-t.left+"px"}),T.on(l,"dblclick",function(t){t=O(l,t.target||t.srcElement);t&&null!=t.hintId&&(i.changeActive(t.hintId),i.pick())}),T.on(l,"click",function(t){t=O(l,t.target||t.srcElement);t&&null!=t.hintId&&(i.changeActive(t.hintId),o.options.completeOnSingleClick&&i.pick())}),T.on(l,"mousedown",function(){setTimeout(function(){s.focus()},20)});C=this.getSelectedHintRange();return 0===C.from&&0===C.to||this.scrollToActive(),T.signal(t,"select",n[this.selectedHint],l.childNodes[this.selectedHint]),!0}function r(t,e,i,n){t.async?t(e,n,i):(i=t(e,i))&&i.then?i.then(n):n(i)}n.prototype={close:function(){this.active()&&(this.cm.state.completionActive=null,this.tick=null,this.options.updateOnCursorActivity&&this.cm.off("cursorActivity",this.activityFunc),this.widget&&this.data&&T.signal(this.data,"close"),this.widget&&this.widget.close(),T.signal(this.cm,"endCompletion",this.cm))},active:function(){return this.cm.state.completionActive==this},pick:function(t,e){var i=t.list[e],n=this;this.cm.operation(function(){i.hint?i.hint(n.cm,t,i):n.cm.replaceRange(M(i),i.from||t.from,i.to||t.to,"complete"),T.signal(t,"pick",i),n.cm.scrollIntoView()}),this.options.closeOnPick&&this.close()},cursorActivity:function(){this.debounce&&(s(this.debounce),this.debounce=0);var t=this.startPos;this.data&&(t=this.data.from);var e,i=this.cm.getCursor(),n=this.cm.getLine(i.line);i.line!=this.startPos.line||n.length-i.ch!=this.startLen-this.startPos.ch||i.ch=this.data.list.length?t=e?this.data.list.length-1:0:t<0&&(t=e?0:this.data.list.length-1),this.selectedHint!=t&&((e=this.hints.childNodes[this.selectedHint])&&(e.className=e.className.replace(" "+F,""),e.removeAttribute("aria-selected")),(e=this.hints.childNodes[this.selectedHint=t]).className+=" "+F,e.setAttribute("aria-selected","true"),this.completion.cm.getInputField().setAttribute("aria-activedescendant",e.id),this.scrollToActive(),T.signal(this.data,"select",this.data.list[this.selectedHint],e))},scrollToActive:function(){var t=this.getSelectedHintRange(),e=this.hints.childNodes[t.from],i=this.hints.childNodes[t.to],t=this.hints.firstChild;e.offsetTopthis.hints.scrollTop+this.hints.clientHeight&&(this.hints.scrollTop=i.offsetTop+i.offsetHeight-this.hints.clientHeight+t.offsetTop)},screenAmount:function(){return Math.floor(this.hints.clientHeight/this.hints.firstChild.offsetHeight)||1},getSelectedHintRange:function(){var t=this.completion.options.scrollMargin||0;return{from:Math.max(0,this.selectedHint-t),to:Math.min(this.data.list.length-1,this.selectedHint+t)}}},T.registerHelper("hint","auto",{resolve:function(t,e){var i,c=t.getHelpers(e,"hint");if(c.length){e=function(t,n,o){var s=function(t,e){if(!t.somethingSelected())return e;for(var i=[],n=0;n,]/,closeOnPick:!0,closeOnUnfocus:!0,updateOnCursorActivity:!0,completeOnSingleClick:!0,container:null,customKeys:null,extraKeys:null,paddingForScrollbar:!0,moveOnOverlap:!0};T.defineOption("hintOptions",null)}); \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 97e1b58e6..023d9fdf2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ = 3.0.3 - xx-xx-2024 * Feature - Add new templates. * Fix - Premium sidebar design issue. +* Dev - Calculation module. * Tweak - Hidden field editable compatibility. * Tweak - Catch mail send error. * Dev - Aweber integration. diff --git a/includes/admin/class-evf-admin-assets.php b/includes/admin/class-evf-admin-assets.php index 039a333dc..5c6a5c29e 100644 --- a/includes/admin/class-evf-admin-assets.php +++ b/includes/admin/class-evf-admin-assets.php @@ -44,6 +44,10 @@ public function admin_styles() { wp_style_add_data( 'everest-forms-admin', 'rtl', 'replace' ); wp_style_add_data( 'everest-forms-admin-menu', 'rtl', 'replace' ); + // Show hint in codemirror. + wp_enqueue_style( 'wp-codemirror' ); + wp_enqueue_style( 'codemirror-hint-css', evf()->plugin_url() . '/assets/css/code-mirror/show-hint.min.css', array( 'wp-codemirror' ), EVF_VERSION ); + // Sitewide menu CSS. wp_enqueue_style( 'everest-forms-admin-menu' ); @@ -329,7 +333,8 @@ public function admin_scripts() { wp_enqueue_script( 'evf-form-builder' ); wp_enqueue_script( 'wp-codemirror' ); - wp_enqueue_style( 'wp-codemirror' ); + // Enqueue additional scripts for hints if not included by default + wp_enqueue_script( 'codemirror-hint', evf()->plugin_url() . '/assets/js/code-mirror/show-hint' . $suffix . '.js', array( 'wp-codemirror' ), EVF_VERSION, true ); // De-register scripts. wp_dequeue_script( 'colorpick' ); diff --git a/includes/class-evf-ajax.php b/includes/class-evf-ajax.php index ca2d617ce..f12cd380e 100644 --- a/includes/class-evf-ajax.php +++ b/includes/class-evf-ajax.php @@ -310,6 +310,12 @@ public static function save_form() { array( 'source' => 'form-save' ) ); $empty_meta_data = array(); + + // Calculation backward compatibility. + $old_calculation_format = 0; + $new_calculation_format = 0; + $not_supported_operator = 0; + if ( ! empty( $data['form_fields'] ) ) { foreach ( $data['form_fields'] as $field_key => $field ) { if ( ! empty( $field['label'] ) ) { @@ -337,6 +343,30 @@ public static function save_form() { if ( empty( $field['meta-key'] ) && ! in_array( $field['type'], array( 'html', 'title', 'captcha', 'divider', 'reset', 'recaptcha', 'hcaptcha', 'turnstile' ), true ) ) { $empty_meta_data[] = $field['label']; } + + if ( isset( $field['enable_calculation'] ) && ! empty( $field['enable_calculation'] ) ) { + if ( isset( $field['calculation_field'] ) && ! empty( $field['calculation_field'] ) ) { + $formula = stripslashes( $field['calculation_field'] ); + $old_formula_pattern = '/\{field_id="([^"]+)"\}/'; + preg_match_all( $old_formula_pattern, $formula, $matches ); + + if ( ! empty( $matches[0] ) ) { + ++$old_calculation_format; + } + + preg_match_all( '/\^/', $formula, $operator ); + + if ( ! empty( $operator[0] ) ) { + ++$not_supported_operator; + } + + $new_formula_pattern = '/\$FIELD_(\d+)/'; + preg_match_all( $new_formula_pattern, $formula, $new_matches ); + if ( ! empty( $new_matches[0] ) ) { + ++$new_calculation_format; + } + } + } } if ( ! empty( $empty_meta_data ) ) { @@ -352,6 +382,34 @@ public static function save_form() { ) ); } + + if ( ! empty( $old_calculation_format ) && ! empty( $new_calculation_format ) ) { + $logger->error( + __( 'Need calculation formula to update.', 'everest-forms' ), + array( 'source' => 'form-save' ) + ); + wp_send_json_error( + array( + 'errorTitle' => esc_html__( 'Need calculation formula to update.', 'everest-forms' ), + /* translators: %s: empty meta data */ + 'errorMessage' => sprintf( esc_html__( 'Please update all formula.', 'everest-forms' ) ), + ) + ); + } + + if ( ! empty( $not_supported_operator ) && ! empty( $new_calculation_format ) ) { + $logger->error( + __( 'Not supported operator.', 'everest-forms' ), + array( 'source' => 'form-save' ) + ); + wp_send_json_error( + array( + 'errorTitle' => esc_html__( 'Not supported operator.', 'everest-forms' ), + /* translators: %s: empty meta data */ + 'errorMessage' => sprintf( esc_html__( '^ operator is not used in latest version. use pow( $FIELD_1, 3 )', 'everest-forms' ) ), + ) + ); + } } // Fix for sorting field ordering. diff --git a/includes/evf-core-functions.php b/includes/evf-core-functions.php index 8493f4903..fad3882e4 100644 --- a/includes/evf-core-functions.php +++ b/includes/evf-core-functions.php @@ -4556,6 +4556,8 @@ function evf_sanitize_builder( $post_data = array() ) { $value = esc_url_raw( $data->value ); } elseif ( preg_match( '/evf_email_message/', $data->name ) || preg_match( '/telegram_message/', $data->name )) { $value = wp_kses_post( $data->value ); + } elseif ( preg_match('/calculation_field/', $data->name) ) { + $value = wp_kses_post( $data->value ); } else { $value = sanitize_text_field( $data->value ); }