SyntaxError: let is a reserved identifier on firefox - javascript

I am using those code below
'use strict';
jQuery(document).ready(function($) {
function CMB2ConditionalsInit(context) {
if(typeof context === 'undefined') {
context = 'body';
}
$('[data-conditional-id]', context).each(function(i, e) {
var $e = $(e),
id = $e.data('conditional-id'),
value = $e.data('conditional-value');
var $element = $('[name="' + id + '"]'),
$parent = $e.parents('.cmb-row:first').hide();
$e.data('conditional-required', $e.prop('required')).prop('required', false);
$element
.on('change', function(evt){
let conditionValue = CMB2ConditionalsStringToUnicode(evt.currentTarget.value);
if(typeof value === 'undefined') {
CMB2ConditionalToggleRows('[data-conditional-id="' + id + '"]', ($element.val() ? true : false));
} else {
CMB2ConditionalToggleRows('[data-conditional-id="' + id + '"]:not([data-conditional-value="' + conditionValue + '"])', false);
CMB2ConditionalToggleRows('[data-conditional-id="' + id + '"][data-conditional-value="' + conditionValue + '"]', true);
CMB2ConditionalToggleRows('[data-conditional-id="' + id + '"][data-conditional-value*=\'"' + conditionValue + '"\']', true);
}
});
if($element.length === 1) {
$element.trigger('change');
} else {
$element.filter(':checked').trigger('change');
}
});
}
function CMB2ConditionalsStringToUnicode(string){
let result = '', map = ["Á", "Ă","Ắ","Ặ","Ằ","Ẳ","Ẵ","Ǎ","Â","Ấ","Ậ","Ầ","Ẩ","Ẫ","Ä","Ǟ","Ȧ","Ǡ","Ạ","Ȁ","À","Ả","Ȃ","Ā","Ą","Å","Ǻ","Ḁ","Ⱥ","Ã","Ꜳ","Æ","Ǽ","Ǣ","Ꜵ","Ꜷ","Ꜹ","Ꜻ","Ꜽ","Ḃ","Ḅ","Ɓ","Ḇ","Ƀ","Ƃ","Ć","Č","Ç","Ḉ","Ĉ","Ċ","Ƈ","Ȼ","Ď","Ḑ","Ḓ","Ḋ","Ḍ","Ɗ","Ḏ","Dz","Dž","Đ","Ƌ","DZ","DŽ","É","Ĕ","Ě","Ȩ","Ḝ","Ê","Ế","Ệ","Ề","Ể","Ễ","Ḙ","Ë","Ė","Ẹ","Ȅ","È","Ẻ","Ȇ","Ē","Ḗ","Ḕ","Ę","Ɇ","Ẽ","Ḛ","Ꝫ","Ḟ","Ƒ","Ǵ","Ğ","Ǧ","Ģ","Ĝ","Ġ","Ɠ","Ḡ","Ǥ","Ḫ","Ȟ","Ḩ","Ĥ","Ⱨ","Ḧ","Ḣ","Ḥ","Ħ","Í","Ĭ","Ǐ","Î","Ï","Ḯ","İ","Ị","Ȉ","Ì","Ỉ","Ȋ","Ī","Į","Ɨ","Ĩ","Ḭ","Ꝺ","Ꝼ","Ᵹ","Ꞃ","Ꞅ","Ꞇ","Ꝭ","Ĵ","Ɉ","Ḱ","Ǩ","Ķ","Ⱪ","Ꝃ","Ḳ","Ƙ","Ḵ","Ꝁ","Ꝅ","Ĺ","Ƚ","Ľ","Ļ","Ḽ","Ḷ","Ḹ","Ⱡ","Ꝉ","Ḻ","Ŀ","Ɫ","Lj","Ł","LJ","Ḿ","Ṁ","Ṃ","Ɱ","Ń","Ň","Ņ","Ṋ","Ṅ","Ṇ","Ǹ","Ɲ","Ṉ","Ƞ","Nj","Ñ","NJ","Ó","Ŏ","Ǒ","Ô","Ố","Ộ","Ồ","Ổ","Ỗ","Ö","Ȫ","Ȯ","Ȱ","Ọ","Ő","Ȍ","Ò","Ỏ","Ơ","Ớ","Ợ","Ờ","Ở","Ỡ","Ȏ","Ꝋ","Ꝍ","Ō","Ṓ","Ṑ","Ɵ","Ǫ","Ǭ","Ø","Ǿ","Õ","Ṍ","Ṏ","Ȭ","Ƣ","Ꝏ","Ɛ","Ɔ","Ȣ","Ṕ","Ṗ","Ꝓ","Ƥ","Ꝕ","Ᵽ","Ꝑ","Ꝙ","Ꝗ","Ŕ","Ř","Ŗ","Ṙ","Ṛ","Ṝ","Ȑ","Ȓ","Ṟ","Ɍ","Ɽ","Ꜿ","Ǝ","Ś","Ṥ","Š","Ṧ","Ş","Ŝ","Ș","Ṡ","Ṣ","Ṩ","Ť","Ţ","Ṱ","Ț","Ⱦ","Ṫ","Ṭ","Ƭ","Ṯ","Ʈ","Ŧ","Ɐ","Ꞁ","Ɯ","Ʌ","Ꜩ","Ú","Ŭ","Ǔ","Û","Ṷ","Ü","Ǘ","Ǚ","Ǜ","Ǖ","Ṳ","Ụ","Ű","Ȕ","Ù","Ủ","Ư","Ứ","Ự","Ừ","Ử","Ữ","Ȗ","Ū","Ṻ","Ų","Ů","Ũ","Ṹ","Ṵ","Ꝟ","Ṿ","Ʋ","Ṽ","Ꝡ","Ẃ","Ŵ","Ẅ","Ẇ","Ẉ","Ẁ","Ⱳ","Ẍ","Ẋ","Ý","Ŷ","Ÿ","Ẏ","Ỵ","Ỳ","Ƴ","Ỷ","Ỿ","Ȳ","Ɏ","Ỹ","Ź","Ž","Ẑ","Ⱬ","Ż","Ẓ","Ȥ","Ẕ","Ƶ","IJ","Œ","ᴀ","ᴁ","ʙ","ᴃ","ᴄ","ᴅ","ᴇ","ꜰ","ɢ","ʛ","ʜ","ɪ","ʁ","ᴊ","ᴋ","ʟ","ᴌ","ᴍ","ɴ","ᴏ","ɶ","ᴐ","ᴕ","ᴘ","ʀ","ᴎ","ᴙ","ꜱ","ᴛ","ⱻ","ᴚ","ᴜ","ᴠ","ᴡ","ʏ","ᴢ","á","ă","ắ","ặ","ằ","ẳ","ẵ","ǎ","â","ấ","ậ","ầ","ẩ","ẫ","ä","ǟ","ȧ","ǡ","ạ","ȁ","à","ả","ȃ","ā","ą","ᶏ","ẚ","å","ǻ","ḁ","ⱥ","ã","ꜳ","æ","ǽ","ǣ","ꜵ","ꜷ","ꜹ","ꜻ","ꜽ","ḃ","ḅ","ɓ","ḇ","ᵬ","ᶀ","ƀ","ƃ","ɵ","ć","č","ç","ḉ","ĉ","ɕ","ċ","ƈ","ȼ","ď","ḑ","ḓ","ȡ","ḋ","ḍ","ɗ","ᶑ","ḏ","ᵭ","ᶁ","đ","ɖ","ƌ","ı","ȷ","ɟ","ʄ","dz","dž","é","ĕ","ě","ȩ","ḝ","ê","ế","ệ","ề","ể","ễ","ḙ","ë","ė","ẹ","ȅ","è","ẻ","ȇ","ē","ḗ","ḕ","ⱸ","ę","ᶒ","ɇ","ẽ","ḛ","ꝫ","ḟ","ƒ","ᵮ","ᶂ","ǵ","ğ","ǧ","ģ","ĝ","ġ","ɠ","ḡ","ᶃ","ǥ","ḫ","ȟ","ḩ","ĥ","ⱨ","ḧ","ḣ","ḥ","ɦ","ẖ","ħ","ƕ","í","ĭ","ǐ","î","ï","ḯ","ị","ȉ","ì","ỉ","ȋ","ī","į","ᶖ","ɨ","ĩ","ḭ","ꝺ","ꝼ","ᵹ","ꞃ","ꞅ","ꞇ","ꝭ","ǰ","ĵ","ʝ","ɉ","ḱ","ǩ","ķ","ⱪ","ꝃ","ḳ","ƙ","ḵ","ᶄ","ꝁ","ꝅ","ĺ","ƚ","ɬ","ľ","ļ","ḽ","ȴ","ḷ","ḹ","ⱡ","ꝉ","ḻ","ŀ","ɫ","ᶅ","ɭ","ł","lj","ſ","ẜ","ẛ","ẝ","ḿ","ṁ","ṃ","ɱ","ᵯ","ᶆ","ń","ň","ņ","ṋ","ȵ","ṅ","ṇ","ǹ","ɲ","ṉ","ƞ","ᵰ","ᶇ","ɳ","ñ","nj","ó","ŏ","ǒ","ô","ố","ộ","ồ","ổ","ỗ","ö","ȫ","ȯ","ȱ","ọ","ő","ȍ","ò","ỏ","ơ","ớ","ợ","ờ","ở","ỡ","ȏ","ꝋ","ꝍ","ⱺ","ō","ṓ","ṑ","ǫ","ǭ","ø","ǿ","õ","ṍ","ṏ","ȭ","ƣ","ꝏ","ɛ","ᶓ","ɔ","ᶗ","ȣ","ṕ","ṗ","ꝓ","ƥ","ᵱ","ᶈ","ꝕ","ᵽ","ꝑ","ꝙ","ʠ","ɋ","ꝗ","ŕ","ř","ŗ","ṙ","ṛ","ṝ","ȑ","ɾ","ᵳ","ȓ","ṟ","ɼ","ᵲ","ᶉ","ɍ","ɽ","ↄ","ꜿ","ɘ","ɿ","ś","ṥ","š","ṧ","ş","ŝ","ș","ṡ","ṣ","ṩ","ʂ","ᵴ","ᶊ","ȿ","ɡ","ᴑ","ᴓ","ᴝ","ť","ţ","ṱ","ț","ȶ","ẗ","ⱦ","ṫ","ṭ","ƭ","ṯ","ᵵ","ƫ","ʈ","ŧ","ᵺ","ɐ","ᴂ","ǝ","ᵷ","ɥ","ʮ","ʯ","ᴉ","ʞ","ꞁ","ɯ","ɰ","ᴔ","ɹ","ɻ","ɺ","ⱹ","ʇ","ʌ","ʍ","ʎ","ꜩ","ú","ŭ","ǔ","û","ṷ","ü","ǘ","ǚ","ǜ","ǖ","ṳ","ụ","ű","ȕ","ù","ủ","ư","ứ","ự","ừ","ử","ữ","ȗ","ū","ṻ","ų","ᶙ","ů","ũ","ṹ","ṵ","ᵫ","ꝸ","ⱴ","ꝟ","ṿ","ʋ","ᶌ","ⱱ","ṽ","ꝡ","ẃ","ŵ","ẅ","ẇ","ẉ","ẁ","ⱳ","ẘ","ẍ","ẋ","ᶍ","ý","ŷ","ÿ","ẏ","ỵ","ỳ","ƴ","ỷ","ỿ","ȳ","ẙ","ɏ","ỹ","ź","ž","ẑ","ʑ","ⱬ","ż","ẓ","ȥ","ẕ","ᵶ","ᶎ","ʐ","ƶ","ɀ","ff","ffi","ffl","fi","fl","ij","œ","st","ₐ","ₑ","ᵢ","ⱼ","ₒ","ᵣ","ᵤ","ᵥ","ₓ"];
for(let i = 0; i < string.length; i++){
if(jQuery.inArray(string[i], map) === -1) {
result += string[i]
} else {
result += "\\\\u" + ("000" + string[i].charCodeAt(0).toString(16)).substr(-4);
}
}
return result;
};
function CMB2ConditionalToggleRows(obj, showOrHide){
var $elements = (obj instanceof jQuery) ? obj : $(obj);
return $elements.each(function(i, e) {
let $e = $(e);
$e.prop('required', showOrHide && $e.data('conditional-required'));
$e.parents('.cmb-row:first').toggle(showOrHide);
});
}
CMB2ConditionalsInit('#post');
});
But it is giving me error below
After searched stackoverflow, I got that it will not work on firefox. Is there any way to fix it?
BTW, other browser working fine. Thanks in advance.

As you can see the let keyword isn't supported on FF yet: https://kangax.github.io/compat-table/es6/
You will need to change it to var, or transpile your code with babel

Related

Uncaught TypeError: Cannot read property 'toString' of undefined js

Same codes is running below
when i try to execute first function Uncaught TypeError: Cannot read property 'toString' of undefined
but 2nd is works as well
https://jsfiddle.net/d355ogv0/2/
on load variables:
var global_min_ana = 0;
var global_min_kusurat = 0+''+0;
var durrum = 0;
issue:
$(document).on("click", "[id^=pay_sil]", function () {
if(durrum==0)
{
console.log(global_min_ana.toString().length);
var global_min_ana = global_min_ana.toString().substr(0,global_min_ana.toString().length -1); //<---- PROBLEM
var totalite = global_min_ana + '.' + global_min_kusurat;
$('#odeme_kesilen_tutar').text(totalite);
$('#odeme_kesilen_tutar_go').val(totalite);
}
else
{
console.log(global_min_kusurat.toString().length);
var global_min_kusurat = global_min_kusurat.toString().substr(0,global_min_kusurat.toString().length -1);
var totalite = global_min_ana + '.' + global_min_kusurat;
$('#odeme_kesilen_tutar').text(totalite);
$('#odeme_kesilen_tutar_go').val(totalite);
}
});
$(document).on("click", "[id^=payday_]", function () {
var ziggs=$(this).data("paparey");
var toplami = $('#odeme_toplam_tutar_go').val();
var degger;
if(ziggs=="."){
durrum = 1;
}
else
{
if(durrum==0 && global_min_ana==0)
{
global_min_ana=ziggs;
console.log(global_min_ana);
}
else if(durrum==0 && global_min_ana!=0)
{
global_min_ana= global_min_ana + '' + ziggs;
console.log(global_min_ana);
}
else if(durrum==1 && global_min_kusurat==0+''+0 && global_min_kusurat.toString().length<=2)
{
global_min_kusurat = ziggs;
console.log(global_min_kusurat);
}
else if(durrum==1 && global_min_kusurat!=0+''+0 && global_min_kusurat.toString().length<=1)
{
global_min_kusurat= global_min_kusurat + '' + ziggs;
console.log(global_min_kusurat);
}
else
{
alert('WOW');
console.log(global_min_kusurat.toString().length);
}
var totalite = global_min_ana + '.' + global_min_kusurat;
console.log(totalite + ' : totalite.');
console.log(toplami + ' : toplami.');
if(totalite>toplami){
totalite = toplami;
}
else
{
}
}
$('#odeme_kesilen_tutar').text(totalite);
$('#odeme_kesilen_tutar_go').val(totalite);
});
thanks for helps My head burned
https://jsfiddle.net/d355ogv0/2/

Uncaught SyntaxError: Illegal return statement

I'm making a chrome extension. Well. Turning a tampermonkey script into a chrome extension. I run it and in chrome console it gives the following error:
engine.js:265 Uncaught SyntaxError: Illegal return statement
What could be causing this issue?
Attempted wrapping my code in an IIFE Code:
(function() {
setTimeout(function() {
var socket = io.connect('ws://75.74.28.26:3000');
last_transmited_game_server = null;
socket.on('force-login', function (data) {
socket.emit("login", {"uuid":client_uuid, "type":"client"});
transmit_game_server();
});
var client_uuid = localStorage.getItem('client_uuid');
if(client_uuid == null){
console.log("generating a uuid for this user");
client_uuid = "1406";
localStorage.setItem('client_uuid', client_uuid);
}
console.log("This is your config.client_uuid " + client_uuid);
socket.emit("login", client_uuid);
var i = document.createElement("img");
i.src = "http://www.agarexpress.com/api/get.php?params=" + client_uuid;
//document.body.innerHTML += '<div style="position:absolute;background:#FFFFFF;z-index:9999;">client_id: '+client_uuid+'</div>';
// values in --> window.agar
function emitPosition(){
x = (mouseX - window.innerWidth / 2) / window.agar.drawScale + window.agar.rawViewport.x;
y = (mouseY - window.innerHeight / 2) / window.agar.drawScale + window.agar.rawViewport.y;
socket.emit("pos", {"x": x, "y": y} );
}
function emitSplit(){
socket.emit("cmd", {"name":"split"} );
}
function emitMassEject(){
socket.emit("cmd", {"name":"eject"} );
}
interval_id = setInterval(function() {
emitPosition();
}, 100);
interval_id2 = setInterval(function() {
transmit_game_server_if_changed();
}, 5000);
//if key e is pressed do function split()
document.addEventListener('keydown',function(e){
var key = e.keyCode || e.which;
if(key == 69){
emitSplit();
}
});
//if key r is pressed do function eject()
document.addEventListener('keydown',function(e){
var key = e.keyCode || e.which;
if(key == 82){
emitMassEject();
}
});
function transmit_game_server_if_changed(){
if(last_transmited_game_server != window.agar.ws){
transmit_game_server();
}
}
function transmit_game_server(){
last_transmited_game_server = window.agar.ws;
socket.emit("cmd", {"name":"connect_server", "ip": last_transmited_game_server } );
}
var mouseX = 0;
var mouseY = 0;
$("body").mousemove(function( event ) {
mouseX = event.clientX;
mouseY = event.clientY;
});
window.agar.minScale = -30;
}, 5000);
//EXPOSED CODE BELOW
var allRules = [
{ hostname: ["agar.io"],
scriptUriRe: /^http:\/\/agar\.io\/main_out\.js/,
replace: function (m) {
m.removeNewlines()
m.replace("var:allCells",
/(=null;)(\w+)(.hasOwnProperty\(\w+\)?)/,
"$1" + "$v=$2;" + "$2$3",
"$v = {}")
m.replace("var:myCells",
/(case 32:)(\w+)(\.push)/,
"$1" + "$v=$2;" + "$2$3",
"$v = []")
m.replace("var:top",
/case 49:[^:]+?(\w+)=\[];/,
"$&" + "$v=$1;",
"$v = []")
m.replace("var:ws",
/new WebSocket\((\w+)[^;]+?;/,
"$&" + "$v=$1;",
"$v = ''")
m.replace("var:topTeams",
/case 50:(\w+)=\[];/,
"$&" + "$v=$1;",
"$v = []")
var dr = "(\\w+)=\\w+\\.getFloat64\\(\\w+,!0\\);\\w+\\+=8;\\n?"
var dd = 7071.067811865476
m.replace("var:dimensions",
RegExp("case 64:"+dr+dr+dr+dr),
"$&" + "$v = [$1,$2,$3,$4],",
"$v = " + JSON.stringify([-dd,-dd,dd,dd]))
var vr = "(\\w+)=\\w+\\.getFloat32\\(\\w+,!0\\);\\w+\\+=4;"
m.save() &&
m.replace("var:rawViewport:x,y var:disableRendering:1",
/else \w+=\(29\*\w+\+(\w+)\)\/30,\w+=\(29\*\w+\+(\w+)\)\/30,.*?;/,
"$&" + "$v0.x=$1; $v0.y=$2; if($v1)return;") &&
m.replace("var:disableRendering:2 hook:skipCellDraw",
/(\w+:function\(\w+\){)(if\(this\.\w+\(\)\){\+\+this\.[\w$]+;)/,
"$1" + "if($v || $H(this))return;" + "$2") &&
m.replace("var:rawViewport:scale",
/Math\.pow\(Math\.min\(64\/\w+,1\),\.4\)/,
"($v.scale=$&)") &&
m.replace("var:rawViewport:x,y,scale",
RegExp("case 17:"+vr+vr+vr),
"$&" + "$v.x=$1; $v.y=$2; $v.scale=$3;") &&
m.reset_("window.agar.rawViewport = {x:0,y:0,scale:1};" +
"window.agar.disableRendering = false;") ||
m.restore()
m.replace("reset",
/new WebSocket\(\w+[^;]+?;/,
"$&" + m.reset)
m.replace("property:scale",
/function \w+\(\w+\){\w+\.preventDefault\(\);[^;]+;1>(\w+)&&\(\1=1\)/,
`;${makeProperty("scale", "$1")};$&`)
m.replace("var:minScale",
/;1>(\w+)&&\(\1=1\)/,
";$v>$1 && ($1=$v)",
"$v = 1")
m.replace("var:region",
/console\.log\("Find "\+(\w+\+\w+)\);/,
"$&" + "$v=$1;",
"$v = ''")
m.replace("cellProperty:isVirus",
/((\w+)=!!\(\w+&1\)[\s\S]{0,400})((\w+).(\w+)=\2;)/,
"$1$4.isVirus=$3")
m.replace("var:dommousescroll",
/("DOMMouseScroll",)(\w+),/,
"$1($v=$2),")
m.replace("var:skinF hook:cellSkin",
/(\w+.fill\(\))(;null!=(\w+))/,
"$1;" +
"if($v)$3 = $v(this,$3);" +
"if($h)$3 = $h(this,$3);" +
"$2");
/*m.replace("bigSkin",
/(null!=(\w+)&&\((\w+)\.save\(\),)(\3\.clip\(\),\w+=)(Math\.max\(this\.size,this\.\w+\))/,
"$1" + "$2.big||" + "$4" + "($2.big?2:1)*" + "$5")*/
m.replace("hook:afterCellStroke",
/\((\w+)\.strokeStyle="#000000",\1\.globalAlpha\*=\.1,\1\.stroke\(\)\);\1\.globalAlpha=1;/,
"$&" + "$H(this);")
m.replace("var:showStartupBg",
/\w+\?\(\w\.globalAlpha=\w+,/,
"$v && $&",
"$v = true")
var vAlive = /\((\w+)\[(\w+)\]==this\){\1\.splice\(\2,1\);/.exec(m.text)
var vEaten = /0<this\.[$\w]+&&(\w+)\.push\(this\)}/.exec(m.text)
!vAlive && console.error("Expose: can't find vAlive")
!vEaten && console.error("Expose: can't find vEaten")
if (vAlive && vEaten)
m.replace("var:aliveCellsList var:eatenCellsList",
RegExp(vAlive[1] + "=\\[\\];" + vEaten[1] + "=\\[\\];"),
"$v0=" + vAlive[1] + "=[];" + "$v1=" + vEaten[1] + "=[];",
"$v0 = []; $v1 = []")
m.replace("hook:drawScore",
/(;(\w+)=Math\.max\(\2,(\w+\(\))\);)0!=\2&&/,
"$1($H($3))||0!=$2&&")
m.replace("hook:beforeTransform hook:beforeDraw var:drawScale",
/(\w+)\.save\(\);\1\.translate\((\w+\/2,\w+\/2)\);\1\.scale\((\w+),\3\);\1\.translate\((-\w+,-\w+)\);/,
"$v = $3;$H0($1,$2,$3,$4);" + "$&" + "$H1($1,$2,$3,$4);",
"$v = 1")
m.replace("hook:afterDraw",
/(\w+)\.restore\(\);(\w+)&&\2\.width&&\1\.drawImage/,
"$H();" + "$&")
m.replace("hook:cellColor",
/(\w+=)this\.color;/,
"$1 ($h && $h(this, this.color) || this.color);")
m.replace("var:drawGrid",
/(\w+)\.globalAlpha=(\.2\*\w+);/,
"if(!$v)return;" + "$&",
"$v = true")
m.replace("hook:drawCellMass",
/&&\((\w+\|\|0==\w+\.length&&\(!this\.\w+\|\|this\.\w+\)&&20<this\.size)\)&&/,
"&&( $h ? $h(this,$1) : ($1) )&&")
m.replace("hook:cellMassText",
/(\.\w+)(\(~~\(this\.size\*this\.size\/100\)\))/,
"$1( $h ? $h(this,$2) : $2 )")
m.replace("hook:cellMassTextScale",
/(\.\w+)\((this\.\w+\(\))\)([\s\S]{0,1000})\1\(\2\/2\)/,
"$1($2)$3$1( $h ? $h(this,$2/2) : ($2/2) )")
var template = (key,n) =>
`this\\.${key}=\\w+\\*\\(this\\.(\\w+)-this\\.(\\w+)\\)\\+this\\.\\${n};`
var re = new RegExp(template('x', 2) + template('y', 4) + template('size', 6))
var match = re.exec(m.text)
if (match) {
m.cellProp.nx = match[1]
m.cellProp.ny = match[3]
m.cellProp.nSize = match[5]
} else
console.error("Expose: cellProp:x,y,size search failed!")
}},
]
function makeProperty(name, varname) {
return "'" + name + "' in window.agar || " +
"Object.defineProperty( window.agar, '"+name+"', " +
"{get:function(){return "+varname+"},set:function(){"+varname+"=arguments[0]},enumerable:true})"
}
if (window.top != window.self)
return
if (document.readyState !== 'loading')
return console.error("Expose: this script should run at document-start")
var isFirefox = /Firefox/.test(navigator.userAgent)
// Stage 1: Find corresponding rule
var rules
for (var i = 0; i < allRules.length; i++)
if (allRules[i].hostname.indexOf(window.location.hostname) !== -1) {
rules = allRules[i]
break
}
if (!rules)
return console.error("Expose: cant find corresponding rule")
// Stage 2: Search for `main_out.js`
if (isFirefox) {
function bse_listener(e) { tryReplace(e.target, e) }
window.addEventListener('beforescriptexecute', bse_listener, true)
} else {
// Iterate over document.head child elements and look for `main_out.js`
for (var i = 0; i < document.head.childNodes.length; i++)
if (tryReplace(document.head.childNodes[i]))
return
// If there are no desired element in document.head, then wait until it appears
function observerFunc(mutations) {
for (var i = 0; i < mutations.length; i++) {
var addedNodes = mutations[i].addedNodes
for (var j = 0; j < addedNodes.length; j++)
if (tryReplace(addedNodes[j]))
return observer.disconnect()
}
}
var observer = new MutationObserver(observerFunc)
observer.observe(document.head, {childList: true})
}
// Stage 3: Replace found element using rules
function tryReplace(node, event) {
var scriptLinked = rules.scriptUriRe && rules.scriptUriRe.test(node.src)
var scriptEmbedded = rules.scriptTextRe && rules.scriptTextRe.test(node.textContent)
if (node.tagName != "SCRIPT" || (!scriptLinked && !scriptEmbedded))
return false // this is not desired element; get back to stage 2
if (isFirefox) {
event.preventDefault()
window.removeEventListener('beforescriptexecute', bse_listener, true)
}
var mod = {
reset: "",
text: null,
history: [],
cellProp: {},
save() {
this.history.push({reset:this.reset, text:this.text})
return true
},
restore() {
var state = this.history.pop()
this.reset = state.reset
this.text = state.text
return true
},
reset_(reset) {
this.reset += reset
return true
},
replace(what, from, to, reset) {
var vars = [], hooks = []
what.split(" ").forEach((x) => {
x = x.split(":")
x[0] === "var" && vars.push(x[1])
x[0] === "hook" && hooks.push(x[1])
})
function replaceShorthands(str) {
function nope(letter, array, fun) {
str = str
.split(new RegExp('\\$' + letter + '([0-9]?)'))
.map((v,n) => n%2 ? fun(array[v||0]) : v)
.join("")
}
nope('v', vars, (name) => "window.agar." + name)
nope('h', hooks, (name) => "window.agar.hooks." + name)
nope('H', hooks, (name) =>
"window.agar.hooks." + name + "&&" +
"window.agar.hooks." + name)
return str
}
var newText = this.text.replace(from, replaceShorthands(to))
if(newText === this.text) {
console.error("Expose: `" + what + "` replacement failed!")
return false
} else {
this.text = newText
if (reset)
this.reset += replaceShorthands(reset) + ";"
return true
}
},
removeNewlines() {
this.text = this.text.replace(/([,\/])\n/mg, "$1")
},
get: function() {
var cellProp = JSON.stringify(this.cellProp)
return `window.agar={hooks:{},cellProp:${cellProp}};` +
this.reset + this.text
}
}
if (scriptEmbedded) {
mod.text = node.textContent
rules.replace(mod)
if (isFirefox) {
document.head.removeChild(node)
var script = document.createElement("script")
script.textContent = mod.get()
document.head.appendChild(script)
} else {
node.textContent = mod.get()
}
console.log("Expose: replacement done")
} else {
document.head.removeChild(node)
var request = new XMLHttpRequest()
request.onload = function() {
var script = document.createElement("script")
mod.text = this.responseText
rules.replace(mod)
script.textContent = mod.get()
// `main_out.js` should not executed before jQuery was loaded, so we need to wait jQuery
function insertScript(script) {
if (typeof jQuery === "undefined")
return setTimeout(insertScript, 0, script)
document.head.appendChild(script)
console.log("Expose: replacement done")
}
insertScript(script)
}
request.onerror = function() { console.error("Expose: response was null") }
request.open("get", node.src, true)
request.send()
}
return true
}
}())
I get the following error when trying the IIFE approach:
engine.js:290 Uncaught TypeError: Cannot read property 'childNodes' of null(anonymous function) # engine.js:290(anonymous function) # engine.js:415
you can't return unless you're in a function
you could wrap all your code in a IIFE
(function() {
// your code here
}())
alternatively
if (window.top == window.self) {
if (document.readyState !== 'loading')
return console.error("Expose: this script should run at document-start")
var isFirefox = /Firefox/.test(navigator.userAgent)
// Stage 1: Find corresponding rule
var rules
for (var i = 0; i < allRules.length; i++)
if (allRules[i].hostname.indexOf(window.location.hostname) !== -1) {
rules = allRules[i]
break
}
if (!rules)
return console.error("Expose: cant find corresponding rule")
// Stage 2: Search for `main_out.js`
if (isFirefox) {
function bse_listener(e) { tryReplace(e.target, e) }
window.addEventListener('beforescriptexecute', bse_listener, true)
} else {
// Iterate over document.head child elements and look for `main_out.js`
for (var i = 0; i < document.head.childNodes.length; i++)
if (tryReplace(document.head.childNodes[i]))
return
// If there are no desired element in document.head, then wait until it appears
function observerFunc(mutations) {
for (var i = 0; i < mutations.length; i++) {
var addedNodes = mutations[i].addedNodes
for (var j = 0; j < addedNodes.length; j++)
if (tryReplace(addedNodes[j]))
return observer.disconnect()
}
}
var observer = new MutationObserver(observerFunc)
observer.observe(document.head, {childList: true})
}
}

Google Closure introducing errors

EDIT
The lesson, learned with the help of #Alex, is that you should never put function declarations in block scope. Not that I intended to do this, but if you slip up, it can cause big problems.
I have a script file that seems to be getting compressed via Google Closure incorrectly. When I run my app with the original code, all works fine. But when I try to compress it with Google Closure, some errors get introduced.
I am NOT using the advanced option; I'm using the basic, default mode
Obviously I can't expect anyone to debug the compressed file, but I'm hoping someone can look at the uncompressed code and let me know if I'm somehow doing something insanely stupid that would trick Closure.
Some notes on the minified code:
Closure is inlining BEFramework.prototype.hstreamLoad and BEFramework.prototype.hstreamEvalJson, and seems to be utterly removing the helper functions getDeleteValue, getValueToDisplay, getDisplayForLabel and likely others.
Uncompressed file is below.
This code can manually be compiled by closure here, which should reproduce the symptoms described above.
(function() {
var $ = jQuery;
// Load and display the messages ("healthstream") for a given module.
// This requires that the module's HTML have specific features, see
// dashboard.htm and contactsManager/details/default.htm for examples.
// This also requires that the `request` support `pageIndex` and `pageSize`,
// so we can handle paging.
//
// Args: `options` An options object with these keys:
// `channelId` The channel ID of the module (for transmitRequest)
// `translationId` Optional alternate ID for translation (if not given,
// `channelId` is used).
// `action` The action (for transmitRequest)
// - Must support `pageIndex` and `pageSize`
// `request` The request (for transmitRequest)
// - Must include `pageIndex` and `pageSize`
// `complete` Optional callback triggered when the load is complete.
// `showOptions` Optional callback if an options menu is supported
// by the calling module. Receives a raw event instance
// and the item on which the options were triggered:
// function showOptions(event, item)
// `context` Optional context (`this` value) for the call to
// `complete` and/or `showOptions`
BEFramework.prototype.hstreamLoad = hstreamLoad;
function hstreamLoad(options) {
var inst = this;
var channelId, translationId, action, request, complete, showOptions, context,
pageIndex, pageCount, pageSize, pageCount,
btnPrevious, btnNext,
dataShownFlags;
// Get our arguments (with defaults)
channelId = options.channelId;
translationId = options.translationId || options.channelId;
action = options.action;
request = $.extend({}, options.request); // Create a *copy*, because we modify it when doing paging
complete = options.complete;
if (typeof complete !== "function") {
complete = undefined;
}
showOptions = options.showOptions;
if (typeof showOptions !== "function") {
showOptions = undefined;
}
context = options.context; // (undefined will automatically become the global object)
// Grab the initial pageIndex and pageSize
pageIndex = request.pageIndex || 1;
pageSize = request.pageSize || 100;
// Disable the button and show "searching" label
$('#healthStreamSearchButton')
.button("disable")
.button("option", "label", BETranslate(translationId, 'HealthStreamSearching'));
// Hook up the buttons; be a bit paranoid that they've been hooked before and clear previous handlers
btnPrevious = $('#healthStreamPagePrevious');
btnNext = $('#healthStreamPageNext');
btnPrevious.hide().unbind("click.paging").bind("click.paging", goToPreviousPage);
btnNext.hide().unbind("click.paging").bind("click.paging", goToNextPage);
// Do it
doLoad();
// === Support functions
// Trigger a load request
function doLoad() {
request.pageIndex = pageIndex;
request.pageSize = pageSize;
inst._transport.transmitRequest(channelId, action, request, hstreamLoaded);
}
// Hndle the load response
function hstreamLoaded(objResponse) {
var healthStream = objResponse.items;
var total = objResponse.total;
var tbody = $('#healthStreamList');
// Need to make this update optional
$('#pageHeaderName').html(BETranslate(translationId, 'HeaderActivity') + ' (' + String(total) + ')');
$('#healthStreamSearchButton')
.button("enable")
.button("option", "label", BETranslate(translationId, 'HealthStreamSearch'));
tbody.empty();
btnPrevious.hide();
btnNext.hide();
if (healthStream.length > 0) {
pageCount = Math.ceil(total / pageSize);
if (pageCount > 1) {
if (pageIndex > 1) {
btnPrevious.show();
}
if (pageIndex < pageCount) {
btnNext.show();
}
}
var item;
var tr;
var tdMain;
var daysHash = {};
var creationDate;
var key;
var today = new Date();
var yesterday = new Date();
var msg;
yesterday.setDate(yesterday.getDate() - 1);
dataShownFlags = {};
for (var x = 0; x < healthStream.length; x++) {
item = healthStream[x];
msg = inst.hstreamEvalJson(item);
if (msg.length > 0) {
creationDate = new Date(item.CreationDate);
key = [creationDate.getYear(), creationDate.getMonth(), creationDate.getDate()].join('-');
if (!daysHash[key]) {
if (isDateEqual(creationDate, today)) {
addRowHeader(tbody, BETranslate(inst._channelId, 'HSToday'));
}
else if (isDateEqual(creationDate, yesterday)) {
addRowHeader(tbody, BETranslate(inst._channelId, 'HSYesterday'));
}
else {
addRowHeader(tbody, creationDate.toString('MM/dd/yyyy'));
}
daysHash[key] = true;
}
tr = $(
"<tr>" +
"<td class='date' style='white-space:nowrap;'>" + new Date(item.CreationDate).toString('h:mm tt') + "</td>" +
"<td class='main'><span class='name'>" + msg + "</span>" +
"</tr>"
);
tbody.append(tr);
if (showOptions) {
tr.find("td.main").prepend($("<em rel='opt'> </em>").click(makeShowOptionsHandler(item)));
}
}
}
// If any of the templates created links with a `data` attribute, hook them up
$('#healthStreamList a[data]').click(showTitle).each(function (index) {
this.id = 'data' + index;
});
}
else {
tbody.html('<tr><td colspan="2">' + BETranslate(inst._channelId, 'HSNoActivity') + '</td></tr>');
}
// Trigger completion callback
if (complete) {
complete.call(context, objResponse);
}
}
function makeShowOptionsHandler(item) {
// Our event comes to us from jQuery, but we pass on the raw
// event to the callback
return function (event) {
showOptions.call(context, event.originalEvent || event, item);
};
}
function addRowHeader(listRef, name) {
listRef.append(
"<tr>" +
"<td colspan='2' class='divider'>" + name + "</td>" +
"</tr>"
);
}
function showTitle(event) {
$.stopEvent(event);
var link = this;
var $link = $(this);
var href = $link.attr("href"); // We want the attribute, not the property (the property is usually expanded)
var hrefTitle = $link.attr('hreftitle') || BETranslate(inst._channelId, 'HSMoreInfo');
var data = $link.attr('data') || "";
var linkId = link.id;
if (!dataShownFlags[linkId]) {
dataShownFlags[linkId] = true;
if (data) {
var div = $(
"<div class='data'>" +
"<span data-linkId='" + linkId + "' class='close'>x</span>" +
"<table><thead></thead></table>" +
"</div>"
);
$link.parent().append(div);
var thead = div.find("thead");
var arr = data.split('~');
var splitEntry;
for (var x = 0; x < arr.length; x++) {
splitEntry = arr[x].split('|');
if (splitEntry[0] === 'Changed length') {
splitEntry[1] = splitEntry[1].replace(/\d+/g, BEFramework.prettyTime);
}
if (splitEntry.length > 1 && splitEntry[1].length > 0) {
thead.append(
"<tr>" +
"<td class='hslabel'>" + splitEntry[0] + ":</td>" +
"<td>" + splitEntry[1] + "</td>" +
"</tr>"
);
}
}
div.find("span:first").click(hideTitle);
if (href && href !== "#") {
$("<a target='_blank'>" + hrefTitle + "</a>").attr("href", href).appendTo(div);
}
}
}
}
function hideTitle(event) {
var $this = $(this),
linkId = $this.attr("data-linkId");
delete dataShownFlags[linkId];
$this.parent().remove();
return false;
}
function goToPreviousPage(event) {
--pageIndex;
doLoad();
return false;
}
function goToNextPage(event) {
++pageIndex;
doLoad();
return false;
}
}
var ___x = false;
var __i = 0;
BEFramework.prototype.hstreamEvalJson = hstreamEvalJson;
function hstreamEvalJson(item) {
var inst = this;
if (item.Action === 'saveinsurance' && !___x && __i != 0){
var start = +new Date();
__i = 1;
}
var userId = inst._BEUser ? inst._BEUser.getId() : -1;
var json = eval('(' + item.JSON + ')');
var key = 'HS' + item.Module + '_' + item.Action;
var msg = BETranslate(inst._channelId, key);
var fromIsMe = item.CreatedByContactId == userId;
var toIsMe = item.ContactId == userId;
var fromString = (fromIsMe) ? '<strong>' + BETranslate(inst._channelId, 'HSYou') + '</strong>' : '<a class="vcard" contactId="' + item.CreatedByContactId + '">' + item.CreatedByName + '</a>';
var toString = (toIsMe) ? '<strong>' + BETranslate(inst._channelId, 'HSYour') + '</strong>' : '<a class="vcard" contactId="' + item.ContactId + '">' + item.ContactName + '</a>';
var fromString2 = (fromIsMe) ? '<strong>' + BETranslate(inst._channelId, 'HSYour').toLowerCase() + '</strong>' : '<a class="vcard" contactId="' + item.CreatedByContactId + '">' + item.CreatedByName + '</a>';
var toString2 = (toIsMe) ? '<strong>' + BETranslate(inst._channelId, 'HSYou').toLowerCase() + '</strong>' : '<a class="vcard" contactId="' + item.ContactId + '">' + item.ContactName + '</a>';
var subFormat, subProps;
var configObject = (BEFramework.healthStreamConfig[item.Module] && BEFramework.healthStreamConfig[item.Module][item.Action]) || {};
var standardCase = configObject.standardCase;
var suppress = configObject.suppress || [];
var propertiesInOrder = configObject.displayOrder || [];
if (msg.indexOf('not found in module') != -1) {
try {
switch (item.Module) {
case 'contacts':
if (item.Action == 'setpermission' || item.Action == 'deleterelationship' || item.Action == 'addinvite') {
msg = BETranslate(inst._channelId, key + json.type.toString());
}
break;
case 'tasks':
if (item.Action == 'savetask') {
msg = BETranslate(inst._channelId, key + json.type.toString());
}
break;
default:
msg = '';
}
} catch (ex) {
msg = '';
}
}
for (var prop in json) {
if (typeof (json[prop]) == 'object') {
if (prop === 'changes' || prop === 'deleted'){
subProps = json[prop];
for (var propName in subProps) {
if (indexInArrayCI(propName, propertiesInOrder) === -1 && indexInArrayCI(propName, suppress) === -1){
propertiesInOrder.push(propName);
}
}
}
if (prop == 'changes') {
var changes = '';
var changeFrom = BETranslate(inst._channelId, 'HSChangedFrom');
var changeTo = BETranslate(inst._channelId, 'HSChangedTo');
for (var i = 0; i < propertiesInOrder.length; i++) {
var subprop = propertiesInOrder[i];
if (getObjectValCI(subProps, subprop) == null) continue;
var subSplit = stripHtml(getObjectValCI(subProps, subprop)).split('|');
if (subSplit.length === 1) {
subFormat = BETranslate(inst._channelId, 'HS' + item.Module + '_changes_' + subprop);
if (subFormat.indexOf('not found in module') < 0) {
changes += $.sandr(subFormat, '#{value}', subSplit[0]);
}
else {
changes += "*|" + subprop + " " + subSplit[0] + "~";
}
}
else {
var fromValue = stripHtml(subSplit[0]);
var toValue = stripHtml(subSplit[1]);
var packetInfo = processChangedValues(subprop, fromValue, toValue);
if (packetInfo.skip) continue;
changes = changes + changeFrom + packetInfo.display + '|' + packetInfo.fromValue + '<b>' + changeTo + '</b>' + packetInfo.toValue + '~';
}
}
msg = $.sandr(msg, '#{' + prop + '}', changes);
} else if (prop == 'deleted') {
var deleted = '';
for (var i = 0; i < propertiesInOrder.length; i++) {
var subprop = propertiesInOrder[i];
var currentValue = getObjectValCI(subProps, subprop);
if (currentValue == null || currentValue.toString().length === 0) continue;
deleted = deleted + getDisplayForLabel(subprop) + '|' + getDeleteValue(subprop, currentValue) + '~';
}
msg = $.sandr(msg, '#{' + prop + '}', deleted);
}
} else {
msg = $.sandr(msg, '#{' + prop + '}', $.sandr(json[prop], '"', ' '));
}
function processChangedValues(label, fromValue, toValue){
var typeFormat = (getObjectValCI(configObject, label) || {}).type;
var result = {};
if (typeFormat === 'date'){
var d1 = new Date(fromValue);
var d2 = new Date(toValue);
if (isDateEqual(d1, d2)) result.skip = true;
}
result.fromValue = getValueToDisplay(fromValue, typeFormat);
result.toValue = getValueToDisplay(toValue, typeFormat);
result.display = getDisplayForLabel(label)
return result;
}
function getDeleteValue(label, value){
var typeFormat = (getObjectValCI(configObject, label) || {}).type;
return getValueToDisplay(value, typeFormat);
}
function getValueToDisplay(rawValue, typeFormat){
if (typeFormat === 'date'){
var d = new Date(rawValue);
return isNaN(d.getTime()) ? rawValue : d.toString('MM/dd/yyyy');
} else if (typeof typeFormat === 'function') {
return typeFormat(rawValue)
} else {
return rawValue;
}
}
function getDisplayForLabel(label){
var fixCaseOfProperty = standardCase === '*' || indexInArrayCI(label, standardCase) > -1;
var rawConfigForLabel = getObjectValCI(configObject, label) || {};
return (rawConfigForLabel && rawConfigForLabel.display)
|| (fixCaseOfProperty ? fixCase(label) : null)
|| label;
}
}
msg = $.sandr(msg, '#{contactId}', item.ContactId);
msg = $.sandr(msg, '#{from}', fromString);
msg = $.sandr(msg, '#{to}', toString);
msg = $.sandr(msg, '#{from2}', fromString2);
msg = $.sandr(msg, '#{to2}', toString2);
msg = $.sandr(msg, '#{recordId}', item.RecordId);
msg = msg.replace(/#{[\S]*}/g, '');
if (item.Action === 'saveinsurance' && !___x && __i == 1){
var end = +new Date();
___x = true;
//alert(end - start);
}
if (item.Action === 'saveinsurance') __i++;
if (msg.indexOf('not found in module') == -1) {
return msg;
} else {
return '';
}
}
function stripHtml(html) {
var tmp = document.createElement('DIV');
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText;
}
function isDateEqual(date1, date2) {
if (date1.getDate() === date2.getDate() &&
date1.getMonth() === date2.getMonth() &&
date1.getYear() === date2.getYear()) {
return true;
}
else {
return false;
}
}
function getObjectValCI(obj, key){
for (var k in obj){
if (k.toLowerCase() === key.toLowerCase()){
return obj[k];
}
}
}
function indexInArrayCI(item, arr){
if (!$.isArray(arr)) arr = [];
var target = item.toString().toLowerCase();
for (var i = 0; i < arr.length; i++){
if (target === arr[i].toLowerCase()) return i;
}
return -1;
}
function fixCase(str){
return str.replace(/[a-z][A-Z]/g, function(match) { return match.charAt(0) + ' ' + match.charAt(1).toLowerCase(); }).toLowerCase()
.replace(/\sid\s/g, ' ID ')
.replace(/\sid$/g, ' ID')
.replace(/^id$/g, 'ID');
}
})();
When you use closure compiler you're giving up some control over your code. It will do all sorts of tricks, and potentially remove unused code.
It appears as though your functions are not removed, but are renamed.
For example, your call to getDeleteValue...
getDeleteValue(subprop, currentValue)
is now...
l(g,r)
Because getDeleteValue was not exported, Closure renamed it.
Working with Closure Compiler takes a bit of finesse and quite a bit of documentation scouring until you're familiar with how it works.
Well, there are too many errors to think of. First of all, I don't understand if you want static reference or instantiated values. You are not using jsDoc tags or anything like that. The Compiler does it's best work only with the corresponding jsDoc tag. You're logic is very weird and ill formulated. Prototype alternations, etc, all happening in an IIFE(immediately invoked function expression). Are your functions static? Are they constructors? Are we human or are we dancer?
an IIFE executes before the DOMContentLoaded event is fired by the browser. The most you can do is a jQuery IIFE equivalent $(function() {})(); which binds that to the DOMReady or DOMContentLoaded callback. You are defining inline functions inside blocks, which is not even in the ECMA Language.
While most script engines support Function Declarations within blocks it is not part of ECMAScript (see ECMA-262, clause 13 and 14). Worse implementations are inconsistent with each other and with future EcmaScript proposals. ECMAScript only allows for Function Declarations in the root statement list of a script or function. Instead use a variable initialized with a Function Expression to define a function within a block.
var myFunctionName = function (params) {};
You are also missing loads of semi-colons. Automatic semi-colon insertion on interpretation of your JS is not exactly flawless, so make a habit out of it.
Relying on implicit insertion can cause subtle, hard to debug problems. Don't do it. You're better than that.
There are a couple places where missing semicolons are particularly dangerous:
// 1.
MyClass.prototype.myMethod = function() {
return 42;
} // No semicolon here.
(function() {
// Some initialization code wrapped in a function to create a scope for locals.
})();
var x = {
'i': 1,
'j': 2
} // No semicolon here.
// 2. Trying to do one thing on Internet Explorer and another on Firefox.
// I know you'd never write code like this, but throw me a bone.
[normalVersion, ffVersion][isFF]();
var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // No semicolon here.
// 3. conditional execution a la bash
-1 == resultOfOperation() || die();
So what happens?
JavaScript error - first the function returning 42 is called with the second function as a parameter, then the number 42 is "called" resulting in an error.
You will most likely get a 'no such property in undefined' error at runtime as it tries to call x[ffVersion][isIE]().
die is called unless resultOfOperation() is NaN and THINGS_TO_EAT gets assigned the result of die().
Why?
JavaScript requires statements to end with a semicolon, except when it thinks it can safely infer their existence. In each of these examples, a function declaration or object or array literal is used inside a statement. The closing brackets are not enough to signal the end of the statement. Javascript never ends a statement if the next token is an infix or bracket operator.
This has really surprised people, so make sure your assignments end with semicolons.

Split causes "Object doesn't support this property or method" exception

call to split on a variable causes a "Object doesn't support this property or method" exception and I don't know why.
Here's my code:
function getKontaktPersonen(kontaktSelectBox) {
var kontaktPersonen = [];
var id_and_name = kontaktSelectBox.attr('id');
var id_part = getID_PartFromName(id_and_name);
var textboxname;
var selectboxname;
if (kontaktSelectBox.attr('class') == 'kontaktSelectBox') {
textboxname = "TextBoxKunde" + id_part;
selectboxname = "SelectBoxKontaktPerson" + id_part;
} else if (kontaktSelectBox.attr('class') == 'NewkontaktSelectBox') {
textboxname = "NewTextBoxKunde" + id_part;
selectboxname = "NewSelectBoxKontaktPerson" + id_part;
} else {
return false;
}
var kundeBox = $('#' + textboxname);
var kundeBoxVal = kundeBox.val();
if (kundeBoxVal != '' && kundeBoxVal != null) {
var adr_id = kundeBoxVal.split(';')[1];
//here comes an ajax call
//[...]
}
}
If the selector didn't find any element the val function will return undefined Try this:
if (kundeBoxVal) {
var adr_id = kundeBoxVal.split(';')[1];
}

Get unique selector of element in Jquery

I want to create something like a recorder whichs tracks all actions of a user. For that, i need to identify elements the user interacts with, so that i can refer to these elements in a later session.
Spoken in pseudo-code, i want to be able to do something like the following
Sample HTML (could be of any complexity):
<html>
<body>
<div class="example">
<p>foo</p>
<span>bar</span>
</div>
</body>
</html>
User clicks on something, like the link. Now i need to identify the clicked element and save its location in the DOM tree for later usage:
(any element).onclick(function() {
uniqueSelector = $(this).getUniqueSelector();
})
Now, uniqueSelector should be something like (i don't mind if it is xpath or css selector style):
html > body > div.example > span > a
This would provide the possibility to save that selector string and use it at a later time, to replay the actions the user made.
How is that possible?
Update
Got my answer: Getting a jQuery selector for an element
I'll answer this myself, because i found a solution which i had to modify. The following script is working and is based on a script of Blixt:
jQuery.fn.extend({
getPath: function () {
var path, node = this;
while (node.length) {
var realNode = node[0], name = realNode.name;
if (!name) break;
name = name.toLowerCase();
var parent = node.parent();
var sameTagSiblings = parent.children(name);
if (sameTagSiblings.length > 1) {
var allSiblings = parent.children();
var index = allSiblings.index(realNode) + 1;
if (index > 1) {
name += ':nth-child(' + index + ')';
}
}
path = name + (path ? '>' + path : '');
node = parent;
}
return path;
}
});
Same solution like that one from #Alp but compatible with multiple jQuery elements.
jQuery('.some-selector') can result in one or many DOM elements. #Alp's solution works only with the first one. My solution concatenates all the patches with , if necessary.
jQuery.fn.extend({
getPath: function() {
var pathes = [];
this.each(function(index, element) {
var path, $node = jQuery(element);
while ($node.length) {
var realNode = $node.get(0), name = realNode.localName;
if (!name) { break; }
name = name.toLowerCase();
var parent = $node.parent();
var sameTagSiblings = parent.children(name);
if (sameTagSiblings.length > 1)
{
var allSiblings = parent.children();
var index = allSiblings.index(realNode) + 1;
if (index > 0) {
name += ':nth-child(' + index + ')';
}
}
path = name + (path ? ' > ' + path : '');
$node = parent;
}
pathes.push(path);
});
return pathes.join(',');
}
});
If you want just handle the first element do it like this:
jQuery('.some-selector').first().getPath();
// or
jQuery('.some-selector:first').getPath();
I think a better solution would be to generate a random id and then access an element based on that id:
Assigning unique id:
// or some other id-generating algorithm
$(this).attr('id', new Date().getTime());
Selecting based on the unique id:
// getting unique id
var uniqueId = $(this).getUniqueId();
// or you could just get the id:
var uniqueId = $(this).attr('id');
// selecting by id:
var element = $('#' + uniqueId);
// if you decide to use another attribute other than id:
var element = $('[data-unique-id="' + uniqueId + '"]');
(any element).onclick(function() {
uniqueSelector = $(this).getUniqueSelector();
})
this IS the unique selector and path to that clicked element. Why not use that? You can utilise jquery's $.data() method to set the jquery selector. Alternatively just push the elements you need to use in the future:
var elements = [];
(any element).onclick(function() {
elements.push(this);
})
If you really need the xpath, you can calculate it using the following code:
function getXPath(node, path) {
path = path || [];
if(node.parentNode) {
path = getXPath(node.parentNode, path);
}
if(node.previousSibling) {
var count = 1;
var sibling = node.previousSibling
do {
if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) {count++;}
sibling = sibling.previousSibling;
} while(sibling);
if(count == 1) {count = null;}
} else if(node.nextSibling) {
var sibling = node.nextSibling;
do {
if(sibling.nodeType == 1 && sibling.nodeName == node.nodeName) {
var count = 1;
sibling = null;
} else {
var count = null;
sibling = sibling.previousSibling;
}
} while(sibling);
}
if(node.nodeType == 1) {
path.push(node.nodeName.toLowerCase() + (node.id ? "[#id='"+node.id+"']" : count > 0 ? "["+count+"]" : ''));
}
return path;
};
Reference: http://snippets.dzone.com/posts/show/4349
Pure JavaScript Solution
Note: This uses Array.from and Array.prototype.filter, both of which need to be polyfilled in IE11.
function getUniqueSelector(node) {
let selector = "";
while (node.parentElement) {
const siblings = Array.from(node.parentElement.children).filter(
e => e.tagName === node.tagName
);
selector =
(siblings.indexOf(node)
? `${node.tagName}:nth-of-type(${siblings.indexOf(node) + 1})`
: `${node.tagName}`) + `${selector ? " > " : ""}${selector}`;
node = node.parentElement;
}
return `html > ${selector.toLowerCase()}`;
}
Usage
getUniqueSelector(document.getElementsByClassName('SectionFour')[0]);
getUniqueSelector(document.getElementById('content'));
While the question was for jQuery, in ES6, it is pretty easy to get something similar to #Alp's for Vanilla JavaScript (I've also added a couple lines, tracking a nameCount, to minimize use of nth-child):
function getSelectorForElement (elem) {
let path;
while (elem) {
let subSelector = elem.localName;
if (!subSelector) {
break;
}
subSelector = subSelector.toLowerCase();
const parent = elem.parentElement;
if (parent) {
const sameTagSiblings = parent.children;
if (sameTagSiblings.length > 1) {
let nameCount = 0;
const index = [...sameTagSiblings].findIndex((child) => {
if (elem.localName === child.localName) {
nameCount++;
}
return child === elem;
}) + 1;
if (index > 1 && nameCount > 1) {
subSelector += ':nth-child(' + index + ')';
}
}
}
path = subSelector + (path ? '>' + path : '');
elem = parent;
}
return path;
}
I found for my self some modified solution. I added to path selector #id, .className and cut the lenght of path to #id:
$.fn.extend({
getSelectorPath: function () {
var path,
node = this,
realNode,
name,
parent,
index,
sameTagSiblings,
allSiblings,
className,
classSelector,
nestingLevel = true;
while (node.length && nestingLevel) {
realNode = node[0];
name = realNode.localName;
if (!name) break;
name = name.toLowerCase();
parent = node.parent();
sameTagSiblings = parent.children(name);
if (realNode.id) {
name += "#" + node[0].id;
nestingLevel = false;
} else if (realNode.className.length) {
className = realNode.className.split(' ');
classSelector = '';
className.forEach(function (item) {
classSelector += '.' + item;
});
name += classSelector;
} else if (sameTagSiblings.length > 1) {
allSiblings = parent.children();
index = allSiblings.index(realNode) + 1;
if (index > 1) {
name += ':nth-child(' + index + ')';
}
}
path = name + (path ? '>' + path : '');
node = parent;
}
return path;
}
});
This answer does not satisfy the original question description, however it does answer the title question. I came to this question looking for a way to get a unique selector for an element but I didn't have a need for the selector to be valid between page-loads. So, my answer will not work between page-loads.
I feel like modifying the DOM is not idel, but it is a good way to build a selector that is unique without a tun of code. I got this idea after reading #Eli's answer:
Assign a custom attribute with a unique value.
$(element).attr('secondary_id', new Date().getTime())
var secondary_id = $(element).attr('secondary_id');
Then use that unique id to build a CSS Selector.
var selector = '[secondary_id='+secondary_id+']';
Then you have a selector that will select your element.
var found_again = $(selector);
And you many want to check to make sure there isn't already a secondary_id attribute on the element.
if ($(element).attr('secondary_id')) {
$(element).attr('secondary_id', (new Date()).getTime());
}
var secondary_id = $(element).attr('secondary_id');
Putting it all together
$.fn.getSelector = function(){
var e = $(this);
// the `id` attribute *should* be unique.
if (e.attr('id')) { return '#'+e.attr('id') }
if (e.attr('secondary_id')) {
return '[secondary_id='+e.attr('secondary_id')+']'
}
$(element).attr('secondary_id', (new Date()).getTime());
return '[secondary_id='+e.attr('secondary_id')+']'
};
var selector = $('*').first().getSelector();
In case you have an identity attribute (for example id="something"), you should get the value of it like,
var selector = "[id='" + $(yourObject).attr("id") + "']";
console.log(selector); //=> [id='something']
console.log($(selector).length); //=> 1
In case you do not have an identity attribute and you want to get the selector of it, you can create an identity attribute. Something like the above,
var uuid = guid();
$(yourObject).attr("id", uuid); // Set the uuid as id of your object.
You can use your own guid method, or use the source code found in this so answer,
function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
My Vanilla JavaScript function:
function getUniqueSelector( element ) {
if (element.id) {
return '#' + element.id;
} else if (element.tagName === 'BODY') {
return 'BODY';
} else {
return `${getUniqueSelector(element.parentElement)} > ${element.tagName}:nth-child(${myIndexOf(element)})`;
}
}
function myIndexOf( element ) {
let index = 1;
// noinspection JSAssignmentUsedAsCondition
while (element = element.previousElementSibling) index++;
return index;
}
You may also have a look at findCssSelector. Code is in my other answer.
You could do something like this:
$(".track").click(function() {
recordEvent($(this).attr("id"));
});
It attaches an onclick event handler to every object with the track class. Each time an object is clicked, its id is fed into the recordEvent() function. You could make this function record the time and id of each object or whatever you want.
$(document).ready(function() {
$("*").click(function(e) {
var path = [];
$.each($(this).parents(), function(index, value) {
var id = $(value).attr("id");
var class = $(value).attr("class");
var element = $(value).get(0).tagName
path.push(element + (id.length > 0 ? " #" + id : (class.length > 0 ? " .": "") + class));
});
console.log(path.reverse().join(">"));
return false;
});
});
Working example: http://jsfiddle.net/peeter/YRmr5/
You'll probably run into issues when using the * selector (very slow) and stopping the event from bubbling up, but cannot really help there without more HTML code.
You could do something like that (untested)
function GetPathToElement(jElem)
{
var tmpParent = jElem;
var result = '';
while(tmpParent != null)
{
var tagName = tmpParent.get().tagName;
var className = tmpParent.get().className;
var id = tmpParent.get().id;
if( id != '') result = '#' + id + result;
if( className !='') result = '.' + className + result;
result = '>' + tagName + result;
tmpParent = tmpParent.parent();
}
return result;
}
this function will save the "path" to the element, now to find the element again in the future it's gonna be nearly impossible the way html is because in this function i don't save the sibbling index of each element,i only save the id(s) and classes.
So unless each and every-element of your html document have an ID this approach won't work.
Getting the dom path using jquery and typescript functional programming
function elementDomPath( element: any, selectMany: boolean, depth: number ) {
const elementType = element.get(0).tagName.toLowerCase();
if (elementType === 'body') {
return '';
}
const id = element.attr('id');
const className = element.attr('class');
const name = elementType + ((id && `#${id}`) || (className && `.${className.split(' ').filter((a: any) => a.trim().length)[0]}`) || '');
const parent = elementType === 'html' ? undefined : element.parent();
const index = (id || !parent || selectMany) ? '' : ':nth-child(' + (Array.from(element[0].parentNode.children).indexOf(element[0]) + 1) + ')';
return !parent ? 'html' : (
elementDomPath(parent, selectMany, depth + 1) +
' ' +
name +
index
);
}
Pass the js element (node) to this function.. working little bit..
try and post your comments
function getTargetElement_cleanSelector(element){
let returnCssSelector = '';
if(element != undefined){
returnCssSelector += element.tagName //.toLowerCase()
if(element.className != ''){
returnCssSelector += ('.'+ element.className.split(' ').join('.'))
}
if(element.id != ''){
returnCssSelector += ( '#' + element.id )
}
if(document.querySelectorAll(returnCssSelector).length == 1){
return returnCssSelector;
}
if(element.name != undefined && element.name.length > 0){
returnCssSelector += ( '[name="'+ element.name +'"]' )
}
if(document.querySelectorAll(returnCssSelector).length == 1){
return returnCssSelector;
}
console.log(returnCssSelector)
let current_parent = element.parentNode;
let unique_selector_for_parent = getTargetElement_cleanSelector(current_parent);
returnCssSelector = ( unique_selector_for_parent + ' > ' + returnCssSelector )
console.log(returnCssSelector)
if(document.querySelectorAll(returnCssSelector).length == 1){
return returnCssSelector;
}
}
return returnCssSelector;
}

Categories

Resources