window.webscenario_step_edit_popup = new class { /** @type {Overlay} */ #overlay; /** @type {HTMLDivElement} */ #dialogue; /** @type {HTMLFormElement} */ #form; /** @type {HTMLTableElement} */ #query_fields; /** @type {HTMLTableElement} */ #post_fields; init({query_fields, post_fields, variables, headers}) { this.#overlay = overlays_stack.getById('webscenario-step-edit'); this.#dialogue = this.#overlay.$dialogue[0]; this.#form = this.#overlay.$dialogue.$body[0].querySelector('form'); this.#query_fields = document.getElementById('step-query-fields'); this.#post_fields = document.getElementById('step-post-fields'); this.#initQueryFields(query_fields); this.#initPostFields(post_fields); this.#initVariables(variables); this.#initHeaders(headers); document.getElementById('post_type').addEventListener('change', (e) => this.#togglePostType(e)); document.getElementById('retrieve_mode').addEventListener('change', () => this.#updateForm()); this.#form.querySelector('.js-parse-url').addEventListener('click', () => this.#parseUrl()); this.#updateForm(); } submit() { const fields = getFormFields(this.#form); for (const field of ['name', 'url', 'posts', 'timeout', 'required', 'status_codes']) { if (field in fields) { fields[field] = fields[field].trim(); } } for (const field of ['query_fields', 'post_fields', 'variables', 'headers']) { if (field in fields) { for (const pair of Object.values(fields[field])) { pair.name = pair.name.trim(); pair.value = pair.value.trim(); } } } this.#overlay.setLoading(); const curl = new Curl('zabbix.php'); curl.setArgument('action', 'webscenario.step.check'); this.#post(curl.getUrl(), fields, (response) => { overlayDialogueDestroy(this.#overlay.dialogueid); this.#dialogue.dispatchEvent(new CustomEvent('dialogue.submit', {detail: response.body})); }); } #initQueryFields(query_fields) { const $query_fields = jQuery(this.#query_fields); $query_fields.dynamicRows({ template: '#step-query-field-row-tmpl', rows: query_fields }); this.#initTextareaFlexible($query_fields); this.#initSortable($query_fields); } #initPostFields(post_fields) { const $post_fields = jQuery(this.#post_fields); $post_fields.dynamicRows({ template: '#step-post-field-row-tmpl', rows: post_fields }); this.#initTextareaFlexible($post_fields); this.#initSortable($post_fields); } #initVariables(variables) { const $variables = jQuery('#step-variables'); $variables.dynamicRows({ template: '#step-variable-row-tmpl', rows: variables }); this.#initTextareaFlexible($variables); } #initHeaders(headers) { const $headers = jQuery('#step-headers'); $headers.dynamicRows({ template: '#step-header-row-tmpl', rows: headers }); this.#initTextareaFlexible($headers); this.#initSortable($headers); } #initTextareaFlexible($table) { $table .on('afteradd.dynamicRows', () => { jQuery('.form_row:last .', $table).textareaFlexible(); }) .find('.').textareaFlexible(); } #initSortable($table) { $table .sortable({ disabled: $table[0].querySelectorAll('.').length < 2, items: 'tbody .', axis: 'y', containment: 'parent', cursor: 'grabbing', handle: 'div.', tolerance: 'pointer', opacity: 0.6, helper: (e, ui) => { for (const td of ui.find('>td')) { const $td = jQuery(td); $td.css('width', $td.width()); } // When dragging element on Safari, it jumps out of the table. if (SF) { // Move back draggable element to proper position. ui.css('left', '5px'); } return ui; }, start: (e, ui) => { jQuery(ui.placeholder).height(jQuery(ui.helper).height()); }, stop: (e, ui) => { for (const td of ui.item.find('>td')) { jQuery(td).removeAttr('style'); } ui.item.removeAttr('style'); } }) .on('afteradd.dynamicRows afterremove.dynamicRows', () => { const is_disabled = $table[0].querySelectorAll('.').length < 2; for (const drag_icon of $table[0].querySelectorAll('div.')) { drag_icon.classList.toggle('', is_disabled); } $table.sortable({disabled: is_disabled}); }) .trigger('afteradd.dynamicRows'); } #togglePostType(e) { try { this.#updatePosts(e.target.value != ); this.#updateForm(); } catch (error) { this.#form.querySelector('[name="post_type"]:not(:checked)').checked = true; this.#showErrorDialog( + '

' + error, e.target); } } #updatePosts(is_raw) { const posts = document.getElementById('posts'); let pairs = []; if (is_raw) { pairs = this.#parsePostRawToPairs(posts.value.trim()); for (const row of this.#post_fields.querySelectorAll('tbody .')) { row.remove(); } const $table = jQuery(this.#post_fields); const last_row = this.#post_fields.querySelector('tbody tr:last-of-type'); const row_template = new Template(document.getElementById('step-post-field-row-tmpl').innerHTML); const template = document.createElement('template'); $table.data('dynamicRows').counter = 0; for (const pair of pairs) { const data = { name: pair.name, value: pair.value, rowNum: $table.data('dynamicRows').counter++ }; template.innerHTML = row_template.evaluate(data); last_row.before(template.content.firstChild); } $table.trigger('afteradd.dynamicRows'); } else { for (const row of this.#post_fields.querySelectorAll('tbody .')) { const name = row.querySelector('[name$="[name]"]').value; const value = row.querySelector('[name$="[value]"]').value; if (name !== '' || value !== '') { pairs.push({name, value}); } } posts.value = this.#parsePostPairsToRaw(pairs); } } #parsePostPairsToRaw(pairs) { const fields = []; for (const pair of pairs) { if (pair.name === '') { throw ; } const parts = []; parts.push(encodeURIComponent(pair.name.replace(/'/g,'%27').replace(/"/g,'%22'))); if (pair.value !== '') { parts.push(encodeURIComponent(pair.value.replace(/'/g,'%27').replace(/"/g,'%22'))); } fields.push(parts.join('=')); } return fields.join('&'); } #parsePostRawToPairs(value) { if (value === '') { return [{name: '', value: ''}]; } const pairs = []; for (const pair of value.split('&')) { const fields = pair.split('='); if (fields[0] === '') { throw ; } if (fields[0].length > 255) { throw ; } if (fields.length == 1) { fields.push(''); } const malformed = fields.length > 2; const non_printable_chars = fields[0].match(/%[01]/) || fields[1].match(/%[01]/); if (malformed || non_printable_chars) { throw ; } pairs.push({ name: decodeURIComponent(fields[0].replace(/\+/g, ' ')), value: decodeURIComponent(fields[1].replace(/\+/g, ' ')) }) } return pairs; } #showErrorDialog(message, trigger_element) { overlayDialogue({ title: , class: 'modal-popup position-middle', content: jQuery('').html(message), buttons: [{ title: , class: 'btn-alt', focused: true, action: function() {} }] }, jQuery(trigger_element)); } #updateForm() { const post_type = this.#form.querySelector('[name="post_type"]:checked').value; for (const field of this.#form.querySelectorAll('.js-field-post-fields')) { field.style.display = post_type == ? '' : 'none'; } for (const field of this.#form.querySelectorAll('.js-field-posts')) { field.style.display = post_type == ? '' : 'none'; } const retrieve_mode = this.#form.querySelector('[name="retrieve_mode"]:checked').value; const posts_elements = this.#form.querySelectorAll( '[name="post_type"], #step-post-fields textarea, #step-post-fields button, #posts' ); if (retrieve_mode == ) { for (const element of posts_elements) { element.setAttribute('disabled', 'disabled'); } jQuery(this.#post_fields).sortable('disable'); for (const element of this.#post_fields.querySelectorAll('.')) { element.classList.add(''); } } else { for (const element of posts_elements) { element.removeAttribute('disabled'); } if (this.#post_fields.querySelectorAll('.').length > 1) { jQuery(this.#post_fields).sortable('enable'); for (const element of this.#post_fields.querySelectorAll('.')) { element.classList.remove(''); } } jQuery('.', jQuery(this.#post_fields)).textareaFlexible(); } } #parseUrl() { const url = document.getElementById('url'); const parsed_url = parseUrlString(url.value); if (parsed_url === false) { const message = + '

' + ; return this.#showErrorDialog(message, url); } url.value = parsed_url.url; if (!parsed_url.pairs.length) { return; } const $table = jQuery(this.#query_fields); for (const row of this.#query_fields.querySelectorAll('tbody .')) { const name = row.querySelector('[name$="[name]"]').value; const value = row.querySelector('[name$="[value]"]').value; if (name === '' && value === '') { row.remove(); } } const last_row = this.#query_fields.querySelector('tbody tr:last-of-type'); const row_template = new Template(document.getElementById('step-query-field-row-tmpl').innerHTML); const template = document.createElement('template'); for (const pair of parsed_url.pairs) { const data = { name: pair.name, value: pair.value, rowNum: $table.data('dynamicRows').counter++ }; template.innerHTML = row_template.evaluate(data); last_row.before(template.content.firstChild); } $table.trigger('afteradd.dynamicRows'); } #post(url, data, success_callback) { fetch(url, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }) .then((response) => response.json()) .then((response) => { if ('error' in response) { throw {error: response.error}; } return response; }) .then(success_callback) .catch((exception) => { for (const element of this.#form.parentNode.children) { if (element.matches('.msg-good, .msg-bad, .msg-warning')) { element.parentNode.removeChild(element); } } let title, messages; if (typeof exception === 'object' && 'error' in exception) { title = exception.error.title; messages = exception.error.messages; } else { messages = []; } const message_box = makeMessageBox('bad', messages, title)[0]; this.#form.parentNode.insertBefore(message_box, this.#form); }) .finally(() => { this.#overlay.unsetLoading(); }); } };