| 1 |
/*--Start--Attach A Plugin Defined Handler Without Using An Inline Event Attribute*/ |
| 2 |
/* The callers pass a fixed, plugin authored string such as onkeyup="__tagembed__searchGoogleLocation();". |
| 3 |
It never contains user data. It is resolved to the real function and bound with addEventListener, |
| 4 |
so no inline event attribute and no eval is used. */ |
| 5 |
function __tagembed__dialogBindHandler(element, handlerString) { |
| 6 |
if (!element || !handlerString) return; |
| 7 |
let __tagembed__matched = String(handlerString).match(/^\s*on([a-zA-Z]+)\s*=\s*"\s*([A-Za-z0-9_$]+)\s*\(\s*\)\s*;?\s*"\s*$/); |
| 8 |
if (__tagembed__matched) { |
| 9 |
let __tagembed__eventName = __tagembed__matched[1].toLowerCase(); |
| 10 |
let __tagembed__functionName = __tagembed__matched[2]; |
| 11 |
element.addEventListener(__tagembed__eventName, function (event) { |
| 12 |
if (typeof window[__tagembed__functionName] === "function") { |
| 13 |
window[__tagembed__functionName].call(this, event); |
| 14 |
} |
| 15 |
}); |
| 16 |
} |
| 17 |
} |
| 18 |
/*--End--Attach A Plugin Defined Handler Without Using An Inline Event Attribute*/ |
| 19 |
function __tagembed__dialog_form(option = { popupSize: "__tagembed__popup_sm", title: "Action", form: { method: '', cancelButtonText: '', cancelButtonClass: '', buttonText: '', buttonClass: '' }, inputs: [], action: null, cancelAction: null }) { |
| 20 |
let elemId = '__tagembed__dialog_form_id_'; |
| 21 |
let method = (option.form.method) ? option.form.method : 'post'; |
| 22 |
let cancelButtonText = (option.form.cancelButtonText) ? option.form.cancelButtonText : 'Cancel'; |
| 23 |
let cancelButtonClass = (option.form.cancelButtonClass) ? option.form.cancelButtonClass : ''; |
| 24 |
let buttonText = (option.form.buttonText) ? option.form.buttonText : 'Submit'; |
| 25 |
let buttonClass = (option.form.buttonClass) ? option.form.buttonClass : ''; |
| 26 |
|
| 27 |
/* The whole dialog is built with DOM methods. Every untrusted value is assigned through |
| 28 |
textContent or setAttribute, so no markup is ever produced from it. */ |
| 29 |
let overlay = document.createElement('div'); |
| 30 |
overlay.setAttribute('id', elemId); |
| 31 |
overlay.className = '__tagembed__overlay'; |
| 32 |
|
| 33 |
let popupWrap = document.createElement('div'); |
| 34 |
popupWrap.className = '__tagembed__popupwrap ' + (option.popupSize ? option.popupSize : ''); |
| 35 |
overlay.appendChild(popupWrap); |
| 36 |
|
| 37 |
let popupInn = document.createElement('div'); |
| 38 |
popupInn.className = '__tagembed__popupinn'; |
| 39 |
popupWrap.appendChild(popupInn); |
| 40 |
|
| 41 |
let header = document.createElement('div'); |
| 42 |
header.className = '__tagembed__header'; |
| 43 |
let heading = document.createElement('h2'); |
| 44 |
heading.textContent = (option.title === undefined || option.title === null) ? '' : String(option.title); |
| 45 |
header.appendChild(heading); |
| 46 |
popupInn.appendChild(header); |
| 47 |
|
| 48 |
let hasInputs = (option.inputs instanceof Array && option.inputs.length > 0); |
| 49 |
if (hasInputs) { |
| 50 |
let horizontalBorder = document.createElement('hr'); |
| 51 |
horizontalBorder.className = '__tagembed__horizontaborder'; |
| 52 |
popupInn.appendChild(horizontalBorder); |
| 53 |
} |
| 54 |
|
| 55 |
let formEl = document.createElement('form'); |
| 56 |
formEl.setAttribute('method', method); |
| 57 |
formEl.setAttribute('autocomplete', 'off'); |
| 58 |
popupInn.appendChild(formEl); |
| 59 |
|
| 60 |
let formBody = document.createElement('div'); |
| 61 |
formBody.className = '__tagembed__formwbody'; |
| 62 |
formEl.appendChild(formBody); |
| 63 |
|
| 64 |
if (hasInputs) { |
| 65 |
for (let input of option.inputs) { |
| 66 |
let id = (input.id) ? input.id : ''; |
| 67 |
let label = (input.label) ? input.label : ''; |
| 68 |
let name = (input.name) ? input.name : ''; |
| 69 |
let type = (input.type) ? input.type : ''; |
| 70 |
let value = (input.value) ? input.value : ''; |
| 71 |
let otherClass = (input.type === 'checkbox' || input.type === 'radio') ? ' __tagembed__checkboxrow' : ''; |
| 72 |
let placeholder = (input.placeholder) ? input.placeholder : ''; |
| 73 |
let jsFunction = (input.jsFunction) ? input.jsFunction : ''; |
| 74 |
let jsSearchBtnFunction = (input.jsSearchBtnFunction) ? input.jsSearchBtnFunction : ''; |
| 75 |
let extraTag = (input.extraTag) ? input.extraTag : ''; |
| 76 |
let searchBtn = (input.searchBtn) ? input.searchBtn : ''; |
| 77 |
let inputLoader = (input.inputLoader) ? input.inputLoader : ''; |
| 78 |
let tagembedformwrowId = (input.tagembedformwrowId) ? input.tagembedformwrowId : ''; |
| 79 |
|
| 80 |
let row = document.createElement('div'); |
| 81 |
row.setAttribute('id', tagembedformwrowId); |
| 82 |
row.className = '__tagembed__formwrow ' + otherClass; |
| 83 |
row.setAttribute('style', type == "hidden" ? "margin-bottom:0px" : ''); |
| 84 |
formBody.appendChild(row); |
| 85 |
|
| 86 |
if (label) { |
| 87 |
let labelEl = document.createElement('label'); |
| 88 |
labelEl.textContent = label + ' '; |
| 89 |
row.appendChild(labelEl); |
| 90 |
} |
| 91 |
|
| 92 |
if (!["textarea", "file", "select", "checkbox", "radio"].includes(type)) { |
| 93 |
let field = document.createElement('input'); |
| 94 |
field.setAttribute('id', id); |
| 95 |
field.setAttribute('name', name); |
| 96 |
field.setAttribute('value', value); |
| 97 |
field.setAttribute('type', type); |
| 98 |
field.setAttribute('placeholder', placeholder); |
| 99 |
__tagembed__dialogBindHandler(field, jsFunction); |
| 100 |
row.appendChild(field); |
| 101 |
} else if (["textarea"].includes(type)) { |
| 102 |
let field = document.createElement('textarea'); |
| 103 |
field.setAttribute('id', id); |
| 104 |
field.setAttribute('name', name); |
| 105 |
field.setAttribute('value', value); |
| 106 |
field.setAttribute('type', type); |
| 107 |
field.setAttribute('placeholder', placeholder); |
| 108 |
field.setAttribute('rows', '5'); |
| 109 |
__tagembed__dialogBindHandler(field, jsFunction); |
| 110 |
row.appendChild(field); |
| 111 |
} else if (["select"].includes(type)) { |
| 112 |
let field = document.createElement('select'); |
| 113 |
field.setAttribute('id', id); |
| 114 |
field.setAttribute('name', name); |
| 115 |
__tagembed__dialogBindHandler(field, jsFunction); |
| 116 |
for (let index in input.options) { |
| 117 |
let optionEl = document.createElement('option'); |
| 118 |
optionEl.setAttribute('value', input.options[index].value); |
| 119 |
optionEl.textContent = ' ' + input.options[index].name + ' '; |
| 120 |
field.appendChild(optionEl); |
| 121 |
} |
| 122 |
row.appendChild(field); |
| 123 |
} else if (["checkbox"].includes(type)) { |
| 124 |
let field = document.createElement('input'); |
| 125 |
field.setAttribute('id', id); |
| 126 |
field.setAttribute('type', type); |
| 127 |
field.setAttribute('name', name); |
| 128 |
field.setAttribute('value', value); |
| 129 |
__tagembed__dialogBindHandler(field, jsFunction); |
| 130 |
row.appendChild(field); |
| 131 |
} else if (["radio"].includes(type)) { |
| 132 |
for (let index in input.options) { |
| 133 |
let optionWrap = document.createElement('div'); |
| 134 |
row.appendChild(optionWrap); |
| 135 |
if (input.options[index].label) { |
| 136 |
let optionLabel = document.createElement('label'); |
| 137 |
optionLabel.setAttribute('style', 'margin-right:5px;margin-left: 5px;'); |
| 138 |
optionLabel.textContent = input.options[index].label + ' '; |
| 139 |
optionWrap.appendChild(optionLabel); |
| 140 |
} |
| 141 |
let field = document.createElement('input'); |
| 142 |
field.setAttribute('id', id); |
| 143 |
field.setAttribute('name', name); |
| 144 |
field.setAttribute('type', type); |
| 145 |
field.setAttribute('value', input.options[index].value); |
| 146 |
if (input.options[index].checked) field.setAttribute('checked', 'checked'); |
| 147 |
__tagembed__dialogBindHandler(field, jsFunction); |
| 148 |
row.appendChild(field); |
| 149 |
} |
| 150 |
} |
| 151 |
|
| 152 |
if (searchBtn) { |
| 153 |
let searchIcon = document.createElement('i'); |
| 154 |
searchIcon.className = 'fas fa-search'; |
| 155 |
searchIcon.setAttribute('id', '__tagembed__input_search_' + searchBtn); |
| 156 |
searchIcon.setAttribute('aria-hidden', 'true'); |
| 157 |
__tagembed__dialogBindHandler(searchIcon, jsSearchBtnFunction); |
| 158 |
row.appendChild(searchIcon); |
| 159 |
} |
| 160 |
|
| 161 |
if (extraTag) { |
| 162 |
let extraTagEl = document.createElement('span'); |
| 163 |
extraTagEl.className = '__tagembed__extratag'; |
| 164 |
extraTagEl.setAttribute('id', '__tagembed__' + extraTag); |
| 165 |
row.appendChild(extraTagEl); |
| 166 |
} |
| 167 |
|
| 168 |
if (inputLoader) { |
| 169 |
let loaderSpan = document.createElement('span'); |
| 170 |
loaderSpan.setAttribute('id', '__tagembed__' + inputLoader); |
| 171 |
loaderSpan.className = '__tagembed__inputLoader'; |
| 172 |
let loaderImg = document.createElement('img'); |
| 173 |
loaderImg.setAttribute('src', __tagembed__plugin_url_for_js + 'assets/images/loader.gif'); |
| 174 |
loaderImg.setAttribute('alt', 'loader'); |
| 175 |
loaderSpan.appendChild(loaderImg); |
| 176 |
row.appendChild(loaderSpan); |
| 177 |
} |
| 178 |
|
| 179 |
let errorSpan = document.createElement('span'); |
| 180 |
errorSpan.setAttribute('id', '__tagembed__' + name + '_error'); |
| 181 |
errorSpan.className = '__tagembed__error'; |
| 182 |
row.appendChild(errorSpan); |
| 183 |
} |
| 184 |
} |
| 185 |
|
| 186 |
let btnWrap = document.createElement('div'); |
| 187 |
btnWrap.className = '__tagembed__btnwrap'; |
| 188 |
formEl.appendChild(btnWrap); |
| 189 |
|
| 190 |
let okayButton = document.createElement('button'); |
| 191 |
okayButton.setAttribute('type', 'submit'); |
| 192 |
okayButton.className = '__tagembed__okaybtn ' + buttonClass; |
| 193 |
okayButton.setAttribute('id', elemId + 'OkayButton'); |
| 194 |
okayButton.textContent = buttonText; |
| 195 |
btnWrap.appendChild(okayButton); |
| 196 |
|
| 197 |
let cancelButton = document.createElement('button'); |
| 198 |
cancelButton.className = '__tagembed__cancelbtn ' + cancelButtonClass; |
| 199 |
cancelButton.setAttribute('id', elemId + 'CancelButton'); |
| 200 |
cancelButton.textContent = cancelButtonText; |
| 201 |
btnWrap.appendChild(cancelButton); |
| 202 |
|
| 203 |
cancelButton.onclick = function () { |
| 204 |
if (option["cancelAction"]) |
| 205 |
option["cancelAction"](); |
| 206 |
document.querySelector('#' + elemId).remove(); |
| 207 |
}; |
| 208 |
formEl.addEventListener("submit", function (event) { |
| 209 |
event.preventDefault(); |
| 210 |
option["action"](event, new FormData(formEl)); |
| 211 |
}); |
| 212 |
document.body.appendChild(overlay); |
| 213 |
} |
| 214 |
|