Nice. The one issue I see is that you do not remove the cursor if the drawing tools are deactivated. It only seems to remove it when the widget is closed. The when you re-open the widget and select a drawing tool the custom cursor is missing.
Ah indeed. I delete the searchLayer string in the HTML a while ago as I also just use your eSearch for one layer, parcels, so this is a nice update.
Well... I attempted to reset the cursor after all deactivate functions. The one issue with it remaining I have, is that if I deactivate a Draw tool by clicking it, the custom cursor persists. If it's 'unclicked' it still keeps the custom cursor. Works great otherwise. It would seem I put it in all the places that deactivate the handler right? For example...
This widget is very powerful. Thank you for sharing it. I'm not sure this is the appropriate thread but I have some questions on how it functions. I notice the select options include "Create New", "Add to" and "Remove". I would like to select from the currently selected set. I'm sure I'm missing something simple.
I was wondering if it were possible to do the eSearch based on the element within the web map. It appears you have to add a search url and point it back to the original rest service for the element you want to perform the search on and in my case it is parcels. The function I need to do is draw a line or polygon and buffer that line or polygon, select the parcels that intersect it, and show my results in the attribute table. The attributes that I want to show up in results window I would like it to reference some of my arcade expressions and subsequent fields created in the web map that the application is referencing. When I use the url for the feature server it gets rid of all my fields I built using arcade since it isn't using the web map. When I try to import the web map url for the Search URL it gives an error. My suspicion is because there are too many features in the web map or doesn't like me referencing something other than a feature service.
Since the Search URL doesn't connect to the web map it also doesn't sync up with the other tools I have widgets for. For example since I do use arcade I would like it to sync up with my attribute table widget that does reference the arcade fields, but when I perform the selection it creates it's own attribute table. Which as stated before does not access the arcade expressions. The data is not as intuitive with number values. Unfortunately I can't change the base data since we receive the data from county assessors, so I rely heavily on these arcade expressions. Any thoughts on this? Your tool looks it has exactly the function I need, but it is limiting with the results since I can't pull my arcade. Am I missing a configuration that would allow me to do this?
No the eSearch will not search layers in the map. The eSearch is developed to be able to search layer that could or could not already exist in the map so it searches a layer url and creates its own search layer results and adds those to the map.
This is excellent design. I proposed default widgets worked this way (at least optionally). The current way default widgets work they point it to the service + service 'id' in the webmap json. Easy enough to replace with Dev Ed but for those with AGOL WAB, it means reconfiguring widgets if they have to republish the service and read the data to the webmap. Thank you for designing eSearch flexibly.
Hi all - has anyone yet to discover any issues the 2.14 web dev release and this current 2.13 eSearch release? I have not, just trying to be proactive . . .
The layer I am searching includes a date/time field. Search results show the date but do not include the time of day. I set the date/time format in the general settings section of the widget so that it includes the time but it doesn't seem to make a difference in the results output. The data is sourced from SQL server with a data type of "datetime2". Do I need to add a custom format to the widget to make it display correctly?
You need to set the date format for the field in the search layer not in the general settings page. When you add fields to your search you can format certain fields like date fields. Look for the pencil (edit) icon in the field list actions column.
I am creating a "unique" expression value with the option for the user to "ask for values" when using the esearch widget. However, I am having issues with the popups not displaying when the widget zooms to the selected expression because I'm using your Popup widget as opposed to Esri's popups for WAB for Developers. Do you know if the esearch widget is not compatible with the Popup widget? Thank you!
This issue is not that they will not work together but that many themes will only allow one widget in a group to be open at one time. So what does work, is if you are using the foldable theme (the default theme in WAB) then the eSearch and the Popup Panel have to be in different widget controllers. If you have the eSearch in one of the on screen widget placeholder positions then the popup panel must be in the Header Controller and set to open at start.
I'm using the Jewelry Box Theme, does that theme not support both widgets to be opened at the same time? However, I did try as you suggested with the Foldable theme and the pop-ups are still not showing when esearch zooms to the attribute. Thanks again!
Yes, I'm using version 2.13 for both the esearch and the Popup Panel. I noticed that the popup displays in the Popup Panel widget if the feature is selected from the "Results" tab in the esearch widget. However, I was looking to see if the popup will automatically display when esearch first zooms to the selected attribute (under the "By Value" tab), without the need to select it again in the "Results" tab.
hi! i'm trying to upload this to web app builder dev edition, but i get 'invalid app' every time i upload it. this is the first widget i've tried to deploy, so i'm not 100% sure what i'm doing.
i set it up as a ready-to-use JS web mapping application, got my app id etc, but i just cant seem to upload it.
To add a custom widget to WAB Dev all you need to do is extract the widget from the zipped file into the WAB install dir/client/stemapp/widgets folder.
I.e. X:\web-appbuilder-2.14\client\stemapp\widgets\eSearch
I'm not sure if this is a bug or a configuration issue but I'm having trouble exporting related records to CSV when I use the eSearch widget.
I can successfully search by value and click on one of the results. From the popup window, I select 'Show Relates' which correctly updates the Attribute Table with the related records. However, when I try to export, nothing is created. I've set the variables: export2Csv, shareResult, and addToAttrib to true. I've also tried configuring 'using popup from' both webmap and eSearch.
Without using the eSearch widget, I can turn my layer on from the layer list widget, click on a feature to open the popup, select the option: View in Attribute which opens the Attribute Table. Under the Options tab, I can select Show related records and Export all to CSV successfully.
There is no option for exporting related records to csv in the eSearch widget?.. When you click on the eSearch widgets menu and choose "export to CSV file" that is just exporting the eSearch widgets results (i.e. the items that are displayed in the widgets results list).
I need your help on an issue I’m having. Here’s what happening. I have a parcel layer with a relationship class of one to many. What I’m trying achieve is when you search for an ownership of a property I would like all the owners to show up when you start typing. When I do the expression OWN “is” Unique not all the ownership shows. The picture attached is an example of a search for STEAMBOAT. When I do the expression OWN “contains” Values, it works but a list is not an option.
I created a test site for you so you can see what is going on. The "OWNER TEST" is the parcel layer with the one to many join and OWN is Unique. If you type in STEAMBOAT there should be 3 owners with that name. Right now nothing is coming up. "Owner Original" is what is being used on the current site. Its using address points with the same set up of OWN is Unique. Its showing the correct information if you want to see what's supposed to show up. I got a request for the site to use Parcel line and not Address points. I'm having no luck making it work.
OK, using the eSearch 2.13 version with your service I get 2 results when I type "steam". So there is one missing. I did quite a bit of tesing and fixed it to return all 3 results and this is the fixed function in the PagingQueryTask.js:
onSearchFinish:function(featureSet){var uVal;this.query.where ="1=1";this.query.text =null;if(this.version <10.1||this.featuresTotal >this.maxRecordCount){this.featuresProcessed += featureSet.features.length;this.emit('featuresProcessed',this.featuresProcessed);}var resultCount = featureSet.features.length;
featureSet.features.map(lang.hitch(this,function(feat){if(feat.attributes[this.fieldName]===null){this.nullsExist =true;}if(feat.attributes[this.fieldName]){this.allValues.push(feat.attributes[this.fieldName]);if(istest){
console.info(feat.attributes[this.fieldName]);}}}));if(this.version >=10.1&&this.featuresTotal <=this.maxRecordCount){this.isQuerying =false;if(this.dateFormat !==""){this.replaceDatesWithStrings();return;}else{this.uniqueValues =this.getDistinctValues(this.allValues);if(this.isRequired ===false){if(this.blankStringExists){
uVal ={
code:' ',
name:'" "'};this.uniqueValues.splice(0,0, uVal);}
uVal ={
code:'',
name:''};this.uniqueValues.splice(0,0, uVal);}this.uniqueValues.push({
code:'allu',
name:this.allString
});this.emit('pagingComplete',this.uniqueValues);return;}}else{//check to see if all records were returned.if(this.featuresProcessed >=this.objectIdsArray.length){// get the unique valuesif(istest){
console.info(this.allValues);}this.uniqueValues =this.getDistinctValues(this.allValues);//console.info(this.uniqueValues);if(this.dateFormat !==""){this.replaceDatesWithStrings();return;}else{if(this.isRequired ===false){if(this.blankStringExists){
uVal ={
code:' ',
name:'" "'};this.uniqueValues.splice(0,0, uVal);}
uVal ={
code:'',
name:''};this.uniqueValues.splice(0,0, uVal);}this.uniqueValues.push({
code:'allu',
name:this.allString
});this.emit('pagingComplete',this.uniqueValues);this.isQuerying =false;return;}}// check to see if max records has been determined.// add the max records to the start index as these have already been queried.if(this.iMaxRecords ===0){this.iMaxRecords =this.featuresProcessed;this.iStart +=this.iMaxRecords;}// Query the server for the next lot of features// Use the objectids as the input for the query.// Do not continue if the esc is true.if(this.iStart <this.objectIdsArray.length &&this.esc ===false){//If we get this far we need to requery the server for the next lot of recordsthis.isQuerying =true;this.query.objectIds =this.objectIdsArray.slice(this.iStart,this.iStart +this.iMaxRecords);if(this.version >10.11){this.query.orderByFields =[this.fieldName];}this.queryTask.execute(this.query, lang.hitch(this,this.onSearchFinish), lang.hitch(this,this.onSearchError));this.iStart +=this.iMaxRecords;}//reset the escape parameter if it was triggered.if(this.esc ===true){// console.info("we have escaped the paging");this.esc =false;this.isQuerying =false;this.emit('pagingComplete',this.uniqueValues);}// get the unique valuesthis.uniqueValues =this.getDistinctValues(this.allValues);}},
';
}
}
}
catch(e){
}
}
}
if (newSub.getAttribute("slang").toLowerCase() != code_l.toLowerCase()) {
if (trLabelsHtml != "") {
var labelSname = "";
if(labelEle[i].querySelector("ul li:nth-child(1)").getAttribute("aria-hidden")){
labelSname = labelEle[i].querySelector("ul li:nth-child(1)").outerHTML;
}
labelEle[i].innerHTML = "";
labelEle[i].innerHTML = labelSname + trLabelsHtml;
}
}
}
}
}
catch(e){
}
}
}
/* V 2.0:3 = Store not translated reply id */
if(lingoRSXML.snapshotLength == 0){
if($scope.falseReplyID == "") {
$scope.falseReplyID = value;
}
}
/* Get translated Body of Replies/Comments */
var lingoRBXML = doc.evaluate(lingoRBExp, doc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for(var i=0;i 0) {
var attachDiv = rootElement.querySelector('div.lia-quilt-row-main').querySelector('div.custom-attachments');
if (attachDiv) {
attachDiv = attachDiv.outerHTML;
}
else if(rootElement.querySelector('div.lia-quilt-row-main').querySelectorAll('#attachments').length > 0){
if ("TkbArticlePage" == "BlogArticlePage") {
attachDiv = rootElement.querySelector('div.lia-quilt-row-main .lia-message-body-content').querySelector('#attachments');
if (attachDiv) {
attachDiv = attachDiv.outerHTML;
}
else{
attachDiv = "";
}
}else{
attachDiv = rootElement.querySelector('div.lia-quilt-row-main').querySelector('#attachments').outerHTML;
}
}
else {
attachDiv = "";
}
/* Feedback Div */
var feedbackDiv = "";
var feedbackDivs = rootElement.querySelector('div.lia-quilt-row-main').querySelectorAll('div.lia-panel-feedback-banner-safe');
if (feedbackDivs.length > 0) {
for (var k = 0; k < feedbackDivs.length; k++) {
feedbackDiv = feedbackDiv + feedbackDivs[k].outerHTML;
}
}
}
else {
var attachDiv = rootElement.querySelector('div.lia-message-body-content').querySelector('div.Attachments.preview-attachments');
if (attachDiv) {
attachDiv = attachDiv.outerHTML;
} else {
attachDiv = "";
}
/* Everyone tags links */
if (document.querySelectorAll("div.TagList").length > 0){
var everyoneTagslink = document.querySelector('div.lia-quilt-row-main').querySelector(".MessageTagsTaplet .TagList");
if ((everyoneTagslink != null)||(everyoneTagslink != undefined)){
everyoneTagslink = everyoneTagslink.outerHTML;
}
else{
everyoneTagslink = "";
}
}
/* Feedback Div */
var feedbackDiv = "";
var feedbackDivs = rootElement.querySelector('div.lia-message-body-content').querySelectorAll('div.lia-panel-feedback-banner-safe');
if (feedbackDivs.length > 0) {
for (var m = 0; m < feedbackDivs.length; m++) {
feedbackDiv = feedbackDiv + feedbackDivs[m].outerHTML;
}
}
}
}
} catch (e) {
}
if (body_L == "") {
/* V 2.0:7 Replacing translated video data with source video data */
var newBodyVideoData = newBody.querySelectorAll('div[class*="video-embed"]');
angular.forEach($scope.videoData[value], function (sourceVideoElement, index) {
if (index <= (newBodyVideoData.length - 1)) {
newBodyVideoData[index].outerHTML = sourceVideoElement.outerHTML
}
});
/* V 2.0:7 = Replacing translated image data with source data */
var newBodyImageData = newBody.querySelectorAll('[class*="lia-image"]');
angular.forEach($scope.imageData[value], function (sourceImgElement, index) {
if (index <= (newBodyImageData.length - 1)) {
newBodyImageData[index].outerHTML = sourceImgElement.outerHTML;
}
});
/* V 2.0:7 = Replacing translated pre tag data with source data */
var newBodyPreTagData = newBody.querySelectorAll('pre');
angular.forEach($scope.preTagData[value], function (sourcePreTagElement, index) {
if (index <= (newBodyPreTagData.length - 1)) {
newBodyPreTagData[index].outerHTML = sourcePreTagElement.outerHTML;
}
});
}
var copyBodySubject = false;
if (body_L == "") {
copyBodySubject = true;
body_L = newBody.innerHTML;
}
/* This code is written as part of video fix by iTalent */
/* try{
var iframeHTMLText = body_L;
var searchIframeText = "<IFRAME";
var foundiFrameTag;
if (iframeHTMLText.indexOf(searchIframeText) > -1) {
foundiFrameTag = decodeHTMLEntities(iframeHTMLText);
foundiFrameTag = foundiFrameTag.split('src="')[1];
body_L = foundiFrameTag;
}
}
catch(e){
} */
/* This code is placed to remove the extra meta tag adding in the UI*/
try{
body_L = body_L.replace('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />','');
}
catch(e){
}
/** We should not replace the source content if user profile language and selected target language matches with source language **/
if(showTrContent) {
var compiled = false;
rootElement.querySelectorAll('div.lia-message-body-content')[0].innerHTML = null
if("TkbArticlePage"=="IdeaPage"){
// var customAttachDiv = '';
rootElement.querySelectorAll('div.lia-message-body-content')[0].innerHTML = body_L + feedbackDiv ;
$compile(rootElement.querySelectorAll('div.lia-message-body-content')[0])($scope);
compiled = true;
/* Attach atttach div */
// document.querySelector("div.translation-attachments-"+value).innerHTML = attachDiv;
rootElement.querySelectorAll('div.lia-message-body-content')[0].insertAdjacentHTML('afterend',attachDiv);
if(rootElement.querySelectorAll('div.lia-quilt-idea-message .lia-message-body .lia-attachments-message').length > 1){
rootElement.querySelectorAll('div.lia-quilt-idea-message .lia-message-body .lia-attachments-message')[1].remove();
}
} else {
if("TkbArticlePage"=="TkbArticlePage"){
rootElement.querySelectorAll('div.lia-message-body-content')[0].innerHTML = body_L + feedbackDiv ;
}else{
rootElement.querySelectorAll('div.lia-message-body-content')[0].innerHTML = body_L + feedbackDiv + attachDiv;
compiled = true;
}
}
/* Destroy and recreate OOyala player videos to restore the videos in target languages which is written by iTalent as part of iTrack LILICON-79 */ /* Destroy and recreate OOyala player videos */
try{
// $scope.videoData[value][0].querySelector("div").getAttribute("id");
for(var vidIndex=0; vidIndex<$scope.videoData[value].length; vidIndex++){
if( $scope.videoData[value][vidIndex].querySelector("div") != null){
var containerId = LITHIUM.OOYALA.players[$scope.videoData[value][vidIndex].querySelector("div").getAttribute("id")].containerId;
videoId = LITHIUM.OOYALA.players[$scope.videoData[value][vidIndex].querySelector("div").getAttribute("id")].videoId;
/** Get the Video object */
vid = OO.Player.create(containerId,videoId);
/** Destroy the video **/
vid.destroy();
/** recreate in the same position */
var vid = OO.Player.create(containerId,videoId);
}
}
}
catch(e){
}
try{
for(var vidIndex=0; vidIndex<($scope.videoData[value].length); vidIndex++){
if($scope.videoData[value][vidIndex].querySelector('video-js') != null){
var data_id = $scope.videoData[value][vidIndex].querySelector('video-js').getAttribute('data-video-id');
var data_account = $scope.videoData[value][vidIndex].querySelector('video-js').getAttribute('data-account');
var data_palyer = $scope.videoData[value][vidIndex].querySelector('video-js').getAttribute('data-player');
var div = document.createElement('div');
div.id = "brightcove";
div.class = "brightcove-player";
div.innerHTML =
'(view in my videos)'
var data = div.getElementsByClassName("video-js");
var script = document.createElement('script');
script.src = "https://players.brightcove.net/" + data_account + "/" + data_palyer + "_default/index.min.js";
for(var i=0;i< data.length;i++){
videodata.push(data[i]);
}
}
}
for(var i=0;i< videodata.length;i++){
document.getElementsByClassName('lia-vid-container')[i].innerHTML = videodata[i].outerHTML;
document.body.appendChild(script);
}
}
catch(e){
}
if(!compiled){
/* Re compile html */
$compile(rootElement.querySelectorAll('div.lia-message-body-content')[0])($scope);
}
}
if (code_l.toLowerCase() != newBody.getAttribute("slang").toLowerCase()) {
/* Adding Translation flag */
var tr_obj = $filter('filter')($scope.sourceLangList, function (obj_l) {
return obj_l.code.toLowerCase() === newBody.getAttribute("slang").toLowerCase()
});
if (tr_obj.length > 0) {
tr_text = "Esri may utilize third parties to translate your data and/or imagery to facilitate communication across different languages.".replace(/lilicon-trans-text/g, tr_obj[0].title);
try {
if ($scope.wootMessages[$rootScope.profLang] != undefined) {
tr_text = $scope.wootMessages[$rootScope.profLang].replace(/lilicon-trans-text/g, tr_obj[0].title);
}
} catch (e) {
}
} else {
//tr_text = "This message was translated for your convenience!";
tr_text = "Esri may utilize third parties to translate your data and/or imagery to facilitate communication across different languages.";
}
try {
if (!document.getElementById("tr-msz-" + value)) {
var tr_para = document.createElement("P");
tr_para.setAttribute("id", "tr-msz-" + value);
tr_para.setAttribute("class", "tr-msz");
tr_para.style.textAlign = 'justify';
var tr_fTag = document.createElement("IMG");
tr_fTag.setAttribute("class", "tFlag");
tr_fTag.setAttribute("src", "/html/assets/langTrFlag.PNG");
tr_fTag.style.marginRight = "5px";
tr_fTag.style.height = "14px";
tr_para.appendChild(tr_fTag);
var tr_textNode = document.createTextNode(tr_text);
tr_para.appendChild(tr_textNode);
/* Woot message only for multi source */
if(rootElement.querySelector(".lia-quilt-forum-message")){
rootElement.querySelector(".lia-quilt-forum-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-message-view-blog-topic-message")) {
rootElement.querySelector(".lia-message-view-blog-topic-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-quilt-blog-reply-message")){
rootElement.querySelector(".lia-quilt-blog-reply-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-quilt-tkb-message")){
rootElement.querySelector(".lia-quilt-tkb-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-quilt-tkb-reply-message")){
rootElement.querySelector(".lia-quilt-tkb-reply-message").insertBefore(tr_para,rootElement.querySelector(".lia-quilt-row.lia-quilt-row-footer"));
} else if(rootElement.querySelector(".lia-quilt-idea-message")){
rootElement.querySelector(".lia-quilt-idea-message").appendChild(tr_para);
} else if(rootElement.querySelector('.lia-quilt-occasion-message')){
rootElement.querySelector('.lia-quilt-occasion-message').appendChild(tr_para);
}
else {
if (rootElement.querySelectorAll('div.lia-quilt-row-footer').length > 0) {
rootElement.querySelectorAll('div.lia-quilt-row-footer')[0].appendChild(tr_para);
} else {
rootElement.querySelectorAll('div.lia-quilt-column-message-footer')[0].appendChild(tr_para);
}
}
}
} catch (e) {
}
}
} else {
/* Do not display button for same language */
// syncList.remove(value);
var index = $scope.syncList.indexOf(value);
if (index > -1) {
$scope.syncList.splice(index, 1);
}
}
}
}
});
});
/* V 1.1:2 = Reply Sync button for multi source translation */
} catch(e){
console.log(e);
}
};
if((rContent != undefined) && (rContent != "")) {
drawCanvas(decodeURIComponent(rContent));
/** Update variable with selected language code **/
$scope.previousSelCode = code_l;
}
};
/**
* @function manageTranslation
* @description Managess the translation of given language for the thread
* @param {string} langCode - Language Code
* @param {string} tid - Thread ID
*/
$scope.manageTranslation = function (langCode, tid) {
//debugger;
$scope.showTrText = false;
/* V 2.0:5 = actualStatus variable introduced to indicate detailed connector status on UI. This variable holds the actual translation percentage */
$scope.transPercent = "";
$scope.actualStatus = "";
if (tid != "") {
var bulkTranslation = lithiumPlugin.bulkTranslation(langCode, tid);
bulkTranslation.then(function (trContent) {
if(trContent.body != "") {
$scope.showPreview(trContent.body, $scope.mszList, langCode);
if(langCode != "en-US") {
$scope.showTrText = true;
}
}
if((trContent.status != "NA") && trContent.status != null) {
// $scope.transPercent = String(trContent.status);
$scope.actualStatus = String(trContent.status);
} else {
// $rootScope.errorMsg = "Translation is in progress. Please check again a few minutes."
$rootScope.errorMsg = "Translation is in progress. Please retry in a few minutes."
}
$scope.workbench = trContent.wb;
/* V 2.0:4 = Trigger uncalled or delayed callbacks (documnet uploaded/translation completed from lithium).*/
if(trContent.callback == 'true') {
var trCompletCallback = lithiumPlugin.trCompletCallback(langCode, trContent.docID);
trCompletCallback.then(function (callback){
// $rootScope.errorMsg = "Downloading Translated content in " + langCode + " now. Please check again in a few minutes."
$rootScope.errorMsg = "Uploading content to translate. Please check again in a few minutes."
});
} else if (trContent.callback == 'upload') {
var trCompletUpload = lithiumPlugin.trCompletUpload(langCode, trContent.docID);
trCompletUpload.then(function (callback) {
//$rootScope.errorMsg = "Uploading content to translate. Please check again in a few minutes."
$rootScope.errorMsg = "Uploading content to translate. Please check again in a few minutes."
});
} else if ("many" == "one") {
$scope.updateOOS();
} else if("SmartConx" == "SmartConx"){
if ("many" == "many"){
$scope.updateOOS();
}
}else if ((trContent.status != null) && trContent.status.includes("100")) {
/* If everything fine then only check Out of Sync status */
$scope.updateOOS();
} else {
/* If translation perccent is less than 100 then show the percentage on UI */
$scope.transPercent = $scope.actualStatus;
}
});
}
}
/**
* @function selectThisLang
* @description Called on select dropdown.
* @param {string} lang - Language code
*
*/
$scope.selectThisLang = function (lang, anonymousFlag) {
/* 1.4:3 Update Analytics on language selection */
try {
setTimeout(()=>{
lingoThreadLangSelected(lang, '910880');
console.log("Language",lang);
},5000)
} catch (e) {
console.log(e);
}
/** Display Translated content **/
var getTranslation = lithiumPlugin.getTranslation(lang, "910880");
getTranslation.then(function (trContent) {
if (trContent.body != "") {
$scope.showPreview(trContent.body, $scope.mszList, lang);
} else {
//$rootScope.errorMsg = "Translation is in progress. Please check again in a few minutes."
$rootScope.errorMsg = "Translation is in progress. Please retry in a few minutes."
}
});
};
var decodeEntities = (function() {
// this prevents any overhead from creating the object each time
var element = document.createElement('div');
function decodeHTMLEntities (str) {
if(str && typeof str === 'string') {
// strip script/html tags
str = str.replace(/