/** * @package Joomla.Component.Builder * * @created 30th April, 2015 * @author Llewellyn van der Merwe * @git Joomla Component Builder * @copyright Copyright (C) 2015 Vast Development Method. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE.txt */ /* JS Document */ /** * JS Function to execute the search */ const doSearch = async (signal, tables) => { try { // build form const formData = new FormData(); // load the result table const resultsTable = new DataTable('#search_results_table'); // get the search mode let typeSearch = modeObject.querySelector('input[type=\'radio\']:checked').value; // set some search values let searchValue = searchObject.value; let replaceValue = replaceObject.value; let matchValue = matchObject.checked ? 1 : 0; let wholeValue = wholeObject.checked ? 1 : 0; let regexValue = regexObject.checked ? 1 : 0; // add the form data formData.append('table_name', ''); formData.append('type_search', typeSearch); formData.append('search_value', searchValue); formData.append('replace_value', replaceValue); formData.append('match_case', matchValue); formData.append('whole_word', wholeValue); formData.append('regex_search', regexValue); // update the URL updateUrlQuery(searchValue, replaceValue, matchValue, wholeValue, regexValue, typeSearch); let abort_this_search_values = false; // reset the progress bar searchProgressBarObject.style.width = '0%'; searchProgressBarObject.innerHTML = '0%'; // show the progress bar searchProgressObject.style.display = ''; // hidde the search button startSearchButton.style.display = 'none'; // show the stop search button stopSearchButton.style.display = ''; // start search timer startSearchTimer(); // reset our global counters fieldCount = 0; lineCount = 0; // set our local counters let total = 0; let progress = tables.length; let index; for (index = 0; index < progress; index++) { let tableName = tables[index]; // add the table name formData.set('table_name', tableName); let options = { signal: signal, method: 'POST', // *GET, POST, PUT, DELETE, etc. body: formData } if (abort_this_search_values) { break; } const response = await fetch(UrlAjax + 'doSearch', options).then(response => { total++; // return the json response if (response.ok) { return response.json(); } else { UIkit.notify(Joomla.JText._('COM_COMPONENTBUILDER_THE_SEARCH_PROCESS_HAD_AN_ERROR_WITH_TABLE') + ' ' + tableName, {pos:'top-right', status:'danger'}); } }).then((data) => { if (typeof data.success !== 'undefined') { UIkit.notify(data.success, {pos:'top-right', timeout : 200, status:'success'}); //} else if (typeof data.not_found !== 'undefined') { // UIkit.notify(data.not_found, {pos:'bottom-right', timeout : 200}); } if (typeof data.items !== 'undefined') { addTableItems(resultsTable, data.items, typeSearch); } if (typeof data.fields_count !== 'undefined') { fieldCount += data.fields_count; } if (typeof data.line_count !== 'undefined') { lineCount += data.line_count; } // calculate the percent let percent = 100.0 * (total / progress); // update the progress bar searchProgressObject.style.display = ''; // always make sure it still shows... searchProgressBarObject.style.width = percent.toFixed(2) + '%'; searchProgressBarObject.innerHTML = percent.toFixed(2) + '%'; // when complete hide the progress bar if (progress == total) { let total_field_line = ' ' + fieldCount + ' ' + Joomla.JText._('COM_COMPONENTBUILDER_FIELDS_THAT_HAD') + ' ' + lineCount + ' ' + Joomla.JText._('COM_COMPONENTBUILDER_LINES') + ' '; if (progress == 1) { searchProgressBarObject.innerHTML = Joomla.JText._('COM_COMPONENTBUILDER_SEARCHING') + ' ' + tableName + total_field_line + Joomla.JText._('COM_COMPONENTBUILDER_AND_FINISHED_THE_SEARCH_IN') + ' ' + getSearchLenght() + ' ' + Joomla.JText._('COM_COMPONENTBUILDER_SECONDS'); } else { searchProgressBarObject.innerHTML = Joomla.JText._('COM_COMPONENTBUILDER_SEARCHING') + ' ' + progress + ' ' + Joomla.JText._('COM_COMPONENTBUILDER_TABLES_WITH') + total_field_line + Joomla.JText._('COM_COMPONENTBUILDER_AND_FINISHED_THE_SEARCH_IN') + ' ' + getSearchLenght() + ' ' + Joomla.JText._('COM_COMPONENTBUILDER_SECONDS'); } // show the search button startSearchButton.style.display = ''; // hidde the stop search button stopSearchButton.style.display = 'none'; setTimeout(function () { // hide the progress bar again searchProgressObject.style.display = 'none'; }, 13000); } }).catch(error => { console.log(error); if (error.name === "AbortError") { abort_this_search_values = true; } }); } } catch (error) { console.log(error); } finally { // Executed regardless if we caught the error } }; /** * JS Function to start search timer */ const startSearchTimer = () => { startSearchTime = new Date(); }; /** * JS Function to get search lenght */ const getSearchLenght = () => { // set ending time endSearchTime = new Date(); // get diff in ms var timeDiff = endSearchTime - startSearchTime; // strip the ms timeDiff /= 1000; // get seconds return Math.round(timeDiff); }; /** * JS Function to fetch selected item */ const getSelectedItem = async (table, row, field, line) => { try { // get the search mode let mode = modeObject.querySelector('input[type=\'radio\']:checked').value; // build form const formData = new FormData(); formData.append('field_name', field); formData.append('row_id', row); formData.append('table_name', table); formData.append('search_value', searchObject.value); formData.append('replace_value', replaceObject.value); formData.append('match_case', matchObject.checked ? 1 : 0); formData.append('whole_word', wholeObject.checked ? 1 : 0); formData.append('regex_search', regexObject.checked ? 1 : 0); // get search value if (mode == 1) { // calling URL postURL = UrlAjax + 'getSearchValue'; } else { // add the line value formData.append('line_nr', line); // calling URL postURL = UrlAjax + 'getReplaceValue'; } let options = { method: 'POST', // *GET, POST, PUT, DELETE, etc. body: formData } const response = await fetch(postURL, options).then(response => { if (response.ok) { return response.json(); } }).then((data) => { if (typeof data.success !== 'undefined') { UIkit.notify(data.success, {pos:'top-right', status:'success'}); } if (typeof data.value !== 'undefined') { addSelectedItem(data.value, table, row, field, line); } }).catch(error => { console.log(error); }); } catch (error) { console.log(error); } finally { // Executed regardless if we caught the error } }; /** * JS Function to check if we should save/update the all current found items */ const replaceAllCheck = () => { // get the current searc and replace values let searchValue = searchObject.value; let replaceValue = replaceObject.value; // load question let question = Joomla.JText._('COM_COMPONENTBUILDER_YOUR_ARE_ABOUT_TO_UPDATE_BALLB_VALUES_THAT_CAN_BE_FOUND_IN_THE_DATABASE') + '
' + Joomla.JText._('COM_COMPONENTBUILDER_YOU_WILL_REPLACE') + ': [' + htmlentities(searchValue) + '] ' + Joomla.JText._('COM_COMPONENTBUILDER_WITH') + ': [' + htmlentities(replaceValue) + ']
' + Joomla.JText._('COM_COMPONENTBUILDER_THIS_CAN_NOT_BE_UNDONE_BYOU_HAVE_BEEN_WARNEDB') + '

' + Joomla.JText._('COM_COMPONENTBUILDER_ARE_YOU_THEREFORE_ABSOLUTELY_SURE_YOU_WANT_TO_CONTINUE'); // do check UIkit.modal.confirm(question, function () { // show the search settings again showSearch(); // Create new controller and issue new request controller_replace = new AbortController(); // check if any specific table was set let tables = []; let table = tableObject.value; if (table != -1) { tables.push(table); replaceAll(controller_replace.signal, tables); } else { replaceAll(controller_replace.signal, searchTables); } }, {labels: { Ok: Joomla.JText._('COM_COMPONENTBUILDER_YES_UPDATE_ALL'), Cancel: Joomla.JText._('COM_COMPONENTBUILDER_NO') }}); }; /** * JS Function to execute the search */ const replaceAll = async (signal, tables) => { try { // build form const formData = new FormData(); // get the search mode let typeSearch = modeObject.querySelector('input[type=\'radio\']:checked').value; // set some search values let searchValue = searchObject.value; let replaceValue = replaceObject.value; let matchValue = matchObject.checked ? 1 : 0; let wholeValue = wholeObject.checked ? 1 : 0; let regexValue = regexObject.checked ? 1 : 0; // add the form data formData.append('table_name', ''); formData.append('type_search', typeSearch); formData.append('search_value', searchValue); formData.append('replace_value', replaceValue); formData.append('match_case', matchValue); formData.append('whole_word', wholeValue); formData.append('regex_search', regexValue); // reset the progress bar replaceProgressBarObject.style.width = '0%'; // show the progress bar replaceProgressObject.style.display = ''; let abort_this_replace_values = false; let total = 0; let progress = tables.length; let index; for (index = 0; index < progress; index++) { let tableName = tables[index]; // add the table name formData.set('table_name', tableName); let options = { signal: signal, method: 'POST', // *GET, POST, PUT, DELETE, etc. body: formData } if (abort_this_replace_values) { break; } const response = await fetch(UrlAjax + 'replaceAll', options).then(response => { total++; if (response.ok) { return response.json(); } else { UIkit.notify(Joomla.JText._('COM_COMPONENTBUILDER_THE_REPLACE_PROCESS_HAD_AN_ERROR_WITH_TABLE') + ' ' + tableName, {pos:'top-right', status:'danger'}); } }).then((data) => { if (typeof data.success !== 'undefined') { UIkit.notify(data.success, {pos:'top-right', timeout : 200, status:'success'}); } else if (typeof data.error !== 'undefined') { UIkit.notify(data.error, {pos:'bottom-right', timeout : 200}); } // calculate the percent let percent = 100.0 * (total / progress); // update the progress bar replaceProgressBarObject.style.width = percent.toFixed(2) + '%'; // when complete hide the progress bar if (progress == total) { setTimeout(function () { // hide the progress bar again replaceProgressObject.style.display = 'none'; // we clear the table again clearAll(); // if not reqex we reverse the search for you so you can see the update was a success if (regexValue == 0) { // set the replace value as the search value UIkit.modal.confirm(Joomla.JText._('COM_COMPONENTBUILDER_WOULD_YOU_LIKE_TO_DO_A_REVERSE_SEARCH'), function(){ startNewSearch(replaceValue, searchValue, matchValue, wholeValue, regexValue, 2); }, function () { UIkit.modal.confirm(Joomla.JText._('COM_COMPONENTBUILDER_WOULD_YOU_LIKE_TO_REPEAT_THE_SAME_SEARCH'), function(){ startSearch(); }, function () { clearSearch(); }, {labels: { Ok: Joomla.JText._('COM_COMPONENTBUILDER_YES'), Cancel: Joomla.JText._('COM_COMPONENTBUILDER_NO') }}); }, {labels: { Ok: Joomla.JText._('COM_COMPONENTBUILDER_YES'), Cancel: Joomla.JText._('COM_COMPONENTBUILDER_NO') }}); } else { // else we search it again just to prove its changed UIkit.modal.confirm(Joomla.JText._('COM_COMPONENTBUILDER_WOULD_YOU_LIKE_TO_REPEAT_THE_SAME_SEARCH'), function(){ startSearch(); }, function () { clearSearch(); }, {labels: { Ok: Joomla.JText._('COM_COMPONENTBUILDER_YES'), Cancel: Joomla.JText._('COM_COMPONENTBUILDER_NO') }}); } }, 3000); } }).catch(error => { console.log(error); if (error.name === "AbortError") { abort_this_replace_values = true; } }); } } catch (error) { console.log(error); } finally { // Executed regardless if we caught the error } }; /** * JS Function to check if we should save/update the current selected item */ const setValueCheck = (row, field, table) => { // load question let question = Joomla.JText._('COM_COMPONENTBUILDER_YOUR_ARE_ABOUT_TO_UPDATE_ROW') + ' (' + row + ') -> (' + field + ') ' + Joomla.JText._('COM_COMPONENTBUILDER_FIELD_IN_THE') + ' (' + table + ') ' + Joomla.JText._('COM_COMPONENTBUILDER_TABLE') + '.

' + Joomla.JText._('COM_COMPONENTBUILDER_THIS_CAN_NOT_BE_UNDONE_ARE_YOU_SURE_YOU_WANT_TO_CONTINUE'); // do check UIkit.modal.confirm(question, function () { setValue(row, field, table); }, {labels: { Ok: Joomla.JText._('COM_COMPONENTBUILDER_YES'), Cancel: Joomla.JText._('COM_COMPONENTBUILDER_NO') }}); }; /** * JS Function to set the current selected item */ const setValue = async (row, field, table) => { try { // get the value from the editor let value = editorObject.getValue(); // build form const formData = new FormData(); formData.append('value', value); formData.append('row_id', row); formData.append('field_name', field); formData.append('table_name', table); let options = { method: 'POST', // *GET, POST, PUT, DELETE, etc. body: formData } const response = await fetch(UrlAjax + 'setValue', options).then(response => { if (response.ok) { return response.json(); } }).then((data) => { if (typeof data.success !== 'undefined') { UIkit.notify(data.success, {pos:'top-right', status:'success'}); clearSelectedItem(); tableActiveObject.remove().draw(); } }).catch(error => { console.log(error); }); } catch (error) { console.log(error); } finally { // Executed regardless if we caught the error } }; /** * JS Function to add item to the editor */ const addSelectedItem = async (value, table, row, field, line) => { // display area if (value.length > 1) { // add value to editor editorObject.setValue(value); // set item details notice area itemNoticeObject.style.display = ''; itemEditButtonObject.innerHTML = editButtonSelected; itemTableNameObject.innerHTML = table; itemRowIdObject.innerHTML = row; itemFieldNameObject.innerHTML = field; itemLineNumberObject.innerHTML = line; // set button and editor line if we have a line number if (typeof line == 'number') { // show and set the save button buttonUpdateItemObject.style.display = ''; buttonUpdateItemObject.setAttribute('onclick',"setValueCheck(" + row + ", '" + field + "', '" + table + "');"); // get top of the code line let top = editorObject.charCoords({line: line, ch: 0}, "local").top; // scroll to the line editorObject.scrollTo(null, top - 12); // select the line editorObject.setCursor(line - 1); } else { // no line so no data we can't save this data buttonUpdateItemObject.setAttribute('onclick', ""); buttonUpdateItemObject.style.display = 'none'; } } }; /** * JS Function to clear item from the editor and hide it */ const clearSelectedItem = async () => { // display area editorObject.setValue(''); // clear notice area itemNoticeObject.style.display = 'none'; itemEditButtonObject.innerHTML = '...'; itemTableNameObject.innerHTML = '...'; itemRowIdObject.innerHTML = '...'; itemFieldNameObject.innerHTML = '...'; itemLineNumberObject.innerHTML = '...'; // clear update button buttonUpdateItemObject.setAttribute('onclick', ''); }; /** * JS Function to clear table items */ const clearTableItems = async () => { let table = new DataTable('#search_results_table'); // clear search table.search('').columns().search( '' ); // clear items table.clear().draw( true ); // hide the update all items buttonUpdateAllStyleDisplay('none'); }; /** * JS Function to clear all details of the search */ const clearAll = async () => { // clear all details clearTableItems(); clearSelectedItem(); searchedObject.innerHTML = '....'; }; /** * JS Function to clear the search and replace values */ const clearSearch = async () => { // clear the search and replace values searchObject.value = ''; replaceObject.value = ''; }; /** * JS Function to set the search and replace values */ const startNewSearch = async (search, replace = '', match = 0, whole = 0, regex = 0, mode = 1) => { // redirect to a new search window.location.href = getSearchURL(search, replace, match, whole, regex, mode); }; /** * JS Function to update the URL of the browser with the search query */ const updateUrlQuery = async (search, replace = '', match = 0, whole = 0, regex = 0, mode = 1) => { // update the url query window.history.pushState({}, '', getSearchURL(search, replace, match, whole, regex, mode)); }; /** * JS Function to get the current search URL */ const getSearchURL = (search, replace = '', match = 0, whole = 0, regex = 0, mode = 1) => { // check if its a single table search let table = tableObject.value; let table_name = ''; if (table != -1) { table_name = '&table_name=' + urlencode(table); } // update the type of search if (mode == 1) { return UrlSearch + table_name + '&search_value=' + urlencode(search) + '&type_search=1&match_case=' + match + '&whole_word=' + whole + '®ex_search=' + regex; } else if (mode == 2) { return UrlSearch + table_name + '&search_value=' + urlencode(search) + '&replace_value=' + urlencode(replace) + '&type_search=2&match_case=' + match + '&whole_word=' + whole + '®ex_search=' + regex; } return UrlSearch + table_name; }; /** * JS Function to check if a element has a class */ const hasClass = (elementObject, classNaam) => { return !!elementObject.className.match(new RegExp('(\\s|^)' + classNaam + '(\\s|$)')); }; /** * JS Function add a class from an element */ const addClass = (elementObject, classNaam) => { if (!hasClass(elementObject, classNaam)) { elementObject.className += " " + classNaam; } }; /** * JS Function remove a class from an element */ const removeClass = (elementObject, classNaam) => { if (hasClass(elementObject, classNaam)) { var reg = new RegExp('(\\s|^)' + classNaam + '(\\s|$)'); elementObject.className = elementObject.className.replace(reg, ' '); } }; /** * JS Function to add items to the table */ const addTableItems = async (table, items, typeSearch) => { table.rows.add(items).draw( false ); if (typeSearch == 2) { buttonUpdateAllStyleDisplay(''); // TODO should only show once all items are loaded } else { buttonUpdateAllStyleDisplay('none'); // TODO should only show once all items are loaded } }; /** * JS Function to update the update all button */ const buttonUpdateAllStyleDisplay = async (value) => { buttonUpdateAllObject.forEach((buttonObject) => { buttonObject.style.display = value; }); }; /** * JS Function to execute (A) on search/replace text change , (B) on search options changes */ const startSearch = (field, forced = false) => { // check if we have an Enter click if (field && typeof field.code !== 'undefined' && field.code === "Enter") { forced = true; } // get replace value if set const replaceValue = replaceObject.value; if (replaceValue.length > 0) { // set the searched value replacedObject.innerHTML = htmlentities(replaceValue); } else { replacedObject.innerHTML = ''; } // get search value const searchValue = searchObject.value; if (searchValue.length > 2 || (searchValue.length > 0 && forced)) { // Cancel any ongoing requests if (controller) controller.abort(); // we clear the table again clearAll(); // set the searched value searchedObject.innerHTML = htmlentities(searchValue); // Create new controller and issue new request controller = new AbortController(); // check if any specific table was set let tables = []; let table = tableObject.value; if (table != -1) { tables.push(table); doSearch(controller.signal, tables); } else { doSearch(controller.signal, searchTables); } } else { // Clear the table clearAll(); } }; /** * JS Function to stop a search */ const stopSearch = () => { // Cancel any ongoing requests if (controller) controller.abort(); // show the search button startSearchButton.style.display = ''; // hidde the stop search button stopSearchButton.style.display = 'none'; // remove the progress bar at some point setTimeout(function () { // hide the progress bar again searchProgressObject.style.display = 'none'; }, 13000); } /** * JS Function to hide search settings and show table search */ const showSearch = () => { searchSettingsObject.style.display = ''; searchDetailsObject.style.display = 'none'; replaceDetailsObject.style.display = 'none'; tableSearchObject.style.display = 'none'; tableLengthObject.style.display = 'none'; }; /** * JS Function to show search settings and hide table search */ const hideSearch = () => { searchSettingsObject.style.display = 'none'; searchDetailsObject.style.display = ''; tableSearchObject.style.display = ''; tableLengthObject.style.display = ''; // check if we are in replace mode let mode = modeObject.querySelector('input[type=\'radio\']:checked').value; if (mode == 2) { replaceDetailsObject.style.display = ''; } }; function htmlentities(string, quoteStyle, charset, doubleEncode) { // discuss at: https://locutus.io/php/htmlentities/ // original by: Kevin van Zonneveld (https://kvz.io) // revised by: Kevin van Zonneveld (https://kvz.io) // revised by: Kevin van Zonneveld (https://kvz.io) // improved by: nobbler // improved by: Jack // improved by: RafaƂ Kukawski (https://blog.kukawski.pl) // improved by: Dj (https://locutus.io/php/htmlentities:425#comment_134018) // bugfixed by: Onno Marsman (https://twitter.com/onnomarsman) // bugfixed by: Brett Zamir (https://brett-zamir.me) // input by: Ratheous // note 1: function is compatible with PHP 5.2 and older // example 1: htmlentities('Kevin & van Zonneveld') // returns 1: 'Kevin & van Zonneveld' // example 2: htmlentities("foo'bar","ENT_QUOTES") // returns 2: 'foo'bar' const hashMap = getHtmlTranslationTable('HTML_ENTITIES', quoteStyle) string = string === null ? '' : string + '' if (!hashMap) { return false } if (quoteStyle && quoteStyle === 'ENT_QUOTES') { hashMap["'"] = ''' } doubleEncode = doubleEncode === null || !!doubleEncode const regex = new RegExp('&(?:#\\d+|#x[\\da-f]+|[a-zA-Z][\\da-z]*);|[' + Object.keys(hashMap) .join('') // replace regexp special chars .replace(/([()[\]{}\-.*+?^$|/\\])/g, '\\$1') + ']', 'g') return string.replace(regex, function (ent) { if (ent.length > 1) { return doubleEncode ? hashMap['&'] + ent.substr(1) : ent } return hashMap[ent] }) } function getHtmlTranslationTable(table, quoteStyle) { // eslint-disable-line camelcase // discuss at: https://locutus.io/php/get_html_translation_table/ // original by: Philip Peterson // revised by: Kevin van Zonneveld (https://kvz.io) // bugfixed by: noname // bugfixed by: Alex // bugfixed by: Marco // bugfixed by: madipta // bugfixed by: Brett Zamir (https://brett-zamir.me) // bugfixed by: T.Wild // improved by: KELAN // improved by: Brett Zamir (https://brett-zamir.me) // input by: Frank Forte // input by: Ratheous // note 1: It has been decided that we're not going to add global // note 1: dependencies to Locutus, meaning the constants are not // note 1: real constants, but strings instead. Integers are also supported if someone // note 1: chooses to create the constants themselves. // example 1: get_html_translation_table('HTML_SPECIALCHARS') // returns 1: {'"': '"', '&': '&', '<': '<', '>': '>'} const entities = {} const hashMap = {} let decimal const constMappingTable = {} const constMappingQuoteStyle = {} let useTable = {} let useQuoteStyle = {} // Translate arguments constMappingTable[0] = 'HTML_SPECIALCHARS' constMappingTable[1] = 'HTML_ENTITIES' constMappingQuoteStyle[0] = 'ENT_NOQUOTES' constMappingQuoteStyle[2] = 'ENT_COMPAT' constMappingQuoteStyle[3] = 'ENT_QUOTES' useTable = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS' useQuoteStyle = !isNaN(quoteStyle) ? constMappingQuoteStyle[quoteStyle] : quoteStyle ? quoteStyle.toUpperCase() : 'ENT_COMPAT' if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') { throw new Error('Table: ' + useTable + ' not supported') } entities['38'] = '&' if (useTable === 'HTML_ENTITIES') { entities['160'] = ' ' entities['161'] = '¡' entities['162'] = '¢' entities['163'] = '£' entities['164'] = '¤' entities['165'] = '¥' entities['166'] = '¦' entities['167'] = '§' entities['168'] = '¨' entities['169'] = '©' entities['170'] = 'ª' entities['171'] = '«' entities['172'] = '¬' entities['173'] = '­' entities['174'] = '®' entities['175'] = '¯' entities['176'] = '°' entities['177'] = '±' entities['178'] = '²' entities['179'] = '³' entities['180'] = '´' entities['181'] = 'µ' entities['182'] = '¶' entities['183'] = '·' entities['184'] = '¸' entities['185'] = '¹' entities['186'] = 'º' entities['187'] = '»' entities['188'] = '¼' entities['189'] = '½' entities['190'] = '¾' entities['191'] = '¿' entities['192'] = 'À' entities['193'] = 'Á' entities['194'] = 'Â' entities['195'] = 'Ã' entities['196'] = 'Ä' entities['197'] = 'Å' entities['198'] = 'Æ' entities['199'] = 'Ç' entities['200'] = 'È' entities['201'] = 'É' entities['202'] = 'Ê' entities['203'] = 'Ë' entities['204'] = 'Ì' entities['205'] = 'Í' entities['206'] = 'Î' entities['207'] = 'Ï' entities['208'] = 'Ð' entities['209'] = 'Ñ' entities['210'] = 'Ò' entities['211'] = 'Ó' entities['212'] = 'Ô' entities['213'] = 'Õ' entities['214'] = 'Ö' entities['215'] = '×' entities['216'] = 'Ø' entities['217'] = 'Ù' entities['218'] = 'Ú' entities['219'] = 'Û' entities['220'] = 'Ü' entities['221'] = 'Ý' entities['222'] = 'Þ' entities['223'] = 'ß' entities['224'] = 'à' entities['225'] = 'á' entities['226'] = 'â' entities['227'] = 'ã' entities['228'] = 'ä' entities['229'] = 'å' entities['230'] = 'æ' entities['231'] = 'ç' entities['232'] = 'è' entities['233'] = 'é' entities['234'] = 'ê' entities['235'] = 'ë' entities['236'] = 'ì' entities['237'] = 'í' entities['238'] = 'î' entities['239'] = 'ï' entities['240'] = 'ð' entities['241'] = 'ñ' entities['242'] = 'ò' entities['243'] = 'ó' entities['244'] = 'ô' entities['245'] = 'õ' entities['246'] = 'ö' entities['247'] = '÷' entities['248'] = 'ø' entities['249'] = 'ù' entities['250'] = 'ú' entities['251'] = 'û' entities['252'] = 'ü' entities['253'] = 'ý' entities['254'] = 'þ' entities['255'] = 'ÿ' } if (useQuoteStyle !== 'ENT_NOQUOTES') { entities['34'] = '"' } if (useQuoteStyle === 'ENT_QUOTES') { entities['39'] = ''' } entities['60'] = '<' entities['62'] = '>' // ascii decimals to real symbols for (decimal in entities) { if (entities.hasOwnProperty(decimal)) { hashMap[String.fromCharCode(decimal)] = entities[decimal] } } return hashMap } function urlencode (str) { // discuss at: https://locutus.io/php/urlencode/ // original by: Philip Peterson // improved by: Kevin van Zonneveld (https://kvz.io) // improved by: Kevin van Zonneveld (https://kvz.io) // improved by: Brett Zamir (https://brett-zamir.me) // improved by: Lars Fischer // improved by: Waldo Malqui Silva (https://fayr.us/waldo/) // input by: AJ // input by: travc // input by: Brett Zamir (https://brett-zamir.me) // input by: Ratheous // bugfixed by: Kevin van Zonneveld (https://kvz.io) // bugfixed by: Kevin van Zonneveld (https://kvz.io) // bugfixed by: Joris // reimplemented by: Brett Zamir (https://brett-zamir.me) // reimplemented by: Brett Zamir (https://brett-zamir.me) // note 1: This reflects PHP 5.3/6.0+ behavior // note 1: Please be aware that this function // note 1: expects to encode into UTF-8 encoded strings, as found on // note 1: pages served as UTF-8 // example 1: urlencode('Kevin van Zonneveld!') // returns 1: 'Kevin+van+Zonneveld%21' // example 2: urlencode('https://kvz.io/') // returns 2: 'https%3A%2F%2Fkvz.io%2F' // example 3: urlencode('https://www.google.nl/search?q=Locutus&ie=utf-8') // returns 3: 'https%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3DLocutus%26ie%3Dutf-8' str = (str + '') return encodeURIComponent(str) .replace(/!/g, '%21') .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A') .replace(/~/g, '%7E') .replace(/%20/g, '+') }