forked from joomla/Component-Builder
834 lines
26 KiB
JavaScript
834 lines
26 KiB
JavaScript
/**
|
|
* @package Joomla.Component.Builder
|
|
*
|
|
* @created 30th April, 2015
|
|
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
|
* @git Joomla Component Builder <https://git.vdm.dev/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;
|
|
|
|
// 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', matchObject.checked ? 1 : 0);
|
|
formData.append('whole_word', wholeObject.checked ? 1 : 0);
|
|
formData.append('regex_search', regexObject.checked ? 1 : 0);
|
|
|
|
let abort_this_search_values = false;
|
|
|
|
// reset the progress bar
|
|
searchProgressBarObject.style.width = '0%';
|
|
searchProgressBarObject.innerHTML = '0%';
|
|
|
|
// show the progress bar
|
|
searchProgressObject.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
|
|
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');
|
|
}
|
|
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 = () => {
|
|
// load question
|
|
let question = Joomla.JText._('COM_COMPONENTBUILDER_YOUR_ARE_ABOUT_TO_REPLACE_BALLB_SEARCH_RESULTS') + '<br />' +
|
|
Joomla.JText._('COM_COMPONENTBUILDER_THIS_CAN_NOT_BE_UNDONE_BYOU_HAVE_BEEN_WARNEDB') + '<br /><br />' +
|
|
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(){
|
|
setSearch(replaceValue, searchValue, matchValue, wholeValue, regexValue, 2);
|
|
}, function () {
|
|
UIkit.modal.confirm(Joomla.JText._('COM_COMPONENTBUILDER_WOULD_YOU_LIKE_TO_REPEAT_THE_SAME_SEARCH'), function(){
|
|
onChange();
|
|
}, 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(){
|
|
onChange();
|
|
}, 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') + '.<br /><br />' +
|
|
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');
|
|
table.clear().draw( true );
|
|
|
|
// hide the update all items
|
|
buttonUpdateAllObject.style.display = '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 setSearch = async (search, replace = '', match = 0, whole = 0, regex = 0, mode = 1) => {
|
|
// update the type of search
|
|
if (mode == 1) {
|
|
window.location.href = UrlSearch +
|
|
'&search_value=' + search +
|
|
'&type_search=1&match_case=' + match +
|
|
'&whole_word=' + whole +
|
|
'®ex_search=' + regex;
|
|
} else if (mode == 2) {
|
|
window.location.href = UrlSearch +
|
|
'&search_value=' + search +
|
|
'&replace_value=' + replace +
|
|
'&type_search=2&match_case=' + match +
|
|
'&whole_word=' + whole +
|
|
'®ex_search=' + regex;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 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) {
|
|
buttonUpdateAllObject.style.display = ''; // TODO should only show once all items are loaded
|
|
} else {
|
|
buttonUpdateAllObject.style.display = 'none'; // TODO should only show once all items are loaded
|
|
}
|
|
};
|
|
|
|
/**
|
|
* JS Function to execute (A) on search/replace text change , (B) on search options changes
|
|
*/
|
|
const onChange = () => {
|
|
// 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) {
|
|
// 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 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
|
|
}
|