Comparing values - can not access the name attribute of an object - javascript

I'm trying to mod a javascript game. It has various objects, such as sprites, tiles, items etc.
So far I have been able to compare the name value of a sprite to change the sound that is generated when you interact with it.
ie:
after('startDialog', function () { //works
if (sprite[id].name === "cat")
sounds.meow();
else if (sprite[id].name === "bully1")
sounds.punch();
else if (sprite[id].name === "bully2")
sounds.gunshot();
else
sounds.birdrobin();
});
The problem arises when I try to interact with items. The same code does not work on them...
after('onInventoryChanged', function () { //does not work
if (item[id].name === "smokes"){
sounds.lighter();
} else {
sounds.birdrobin();
}
});
The only differance between the items and sprites is, that sprites are unique, you can not have two sprites with the same name attribute. You can have as many items with the same name as you like on the other hand.
I am buffled though, as both the sprites and items objects are "generated" by the same code and I should be able to access the name variable in items as well...
function parseItem(lines, i) {
var id = getId(lines[i]);
var drwId = null;
var name = null;
//item data
item[id] = {
id : id,
drw : drwId, //drawing id
col : colorIndex,
dlg : dialogId,
name : name
};
return i;
}
function parseSprite(lines, i) {
var id = getId(lines[i]);
var drwId = null;
var name = null;
//sprite data
sprite[id] = {
id : id,
drw : drwId, //drawing id
col : colorIndex,
dlg : dialogId,
inventory : startingInventory,
name : name
};
return i;
}
Any help would be welcome, as I have been stuck here for the last few days.
If I can provide any addtional information, feel free to ask. I just don't want to clutter the question right from the start.
Edit 1:
item[id].name is used to draw the objects on the canvas, so I should be able to access it...
for (id in item) {
worldStr += "ITM " + id + "\n";
worldStr += serializeDrawing( "ITM_" + id );
if (item[id].name != null && item[id].name != undefined) {
/* NAME */
worldStr += "NAME " + item[id].name + "\n";
}
if (item[id].dlg != null) {
worldStr += "DLG " + item[id].dlg + "\n";
}
if (item[id].col != null && item[id].col != undefined && item[id].col != 2) {
/* COLOR OVERRIDE */
worldStr += "COL " + item[id].col + "\n";
}
worldStr += "\n";
}
Edit 2:
I've made a little bit of "progress". Now, onInventoryChange actually does generate a sound, but not the correct one. I have an item with a name smokes and I have an item with a name beer. The sound that is generated is in the else section even when I interact with smokes and beer...
after('onInventoryChanged', function () {
if (item.name === "smokes"){
sounds.lighter();
} else if (item.name === "beer") {
sounds.bottleCap();
} else {
sounds.birdrobin();
}
});
Thank you

Related

Hide all content exception made when URL parameter is used

I want to hide my website content exception made when ?token_code=12345678 is used in URL. This is the code that's not working correctly, it hides website but never shows it:
I'm calling script by www.example.com/?authtoken=12345678
So when that parameter is included in URL it should show website. But it's not displaying it. It's only hiding it.
PS. I'm using cookies to remember "token" :)
HTML:
<body data-token="12345678"> </body>
JS:
//setCookie and readCookie
function SetCookie(e, t, n) {
var r = new Date;
var i = new Date;
if (n == null || n == 0) n = 1;
i.setTime(r.getTime() + 36e5 * 24 * n);
document.cookie = e + "=" + escape(t) + ";expires=" + i.toGMTString()
}
function ReadCookie(e) {
var t = " " + document.cookie;
var n = t.indexOf(" " + e + "=");
if (n == -1) n = t.indexOf(";" + e + "=");
if (n == -1 || e == "") return "";
var r = t.indexOf(";", n + 1);
if (r == -1) r = t.length;
return unescape(t.substring(n + e.length + 2, r))
}
function DeleteCookie(name) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
//capitalzies string
function capitalize(str) {
var first = str.charAt(0).toUpperCase();
str = str.replace(/^.{1}/, first);
return str;
}
// get's the GET paramters like so --> $_GET('var1');
function getVar(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
return (false);
}
// Checks for one of TWO access short codes
// includeOnly && excludeOnly
// If includeOnly is not NULL, then ONLY include
// categories mentioned in that varaible.
// Also, cookie the data, that it's saved.
// Of course, if anyone re-visits the site, and
// re-writes the GET paramter, it'd delete all
// previous data in the cookie.
var token_code = ["authtoken", "excludeOnly"];
var asc = ""; //this is used to select the CURRENT access short code
var tokenValues = [];
//first check if there are ANY get params.
if (getVar(token_code[0]) != false) {
//before writing the inlcude only, delete EXCLUDE only
DeleteCookie(token_code[1]);
SetCookie(token_code[0], getVar(token_code[0]));
}
if (getVar(token_code[1]) != false) {
//before writing the EXCLUDE only, delete include only
DeleteCookie(token_code[0]);
SetCookie(token_code[1], getVar(token_code[1]));
}
//Try and reaad the cookie (there should be a cookie named "includeOnly" or "excludeOnly -- both from token_code)
//includeOnly is present?
if (ReadCookie(token_code[0]).toString().length > 0) {
//defines what the user wants to do. Exlcude or include? when token_code[0] it's include!
asc = token_code[0];
var tokens = ReadCookie(asc).toString();
tokenValues = decodeURIComponent(tokens).split(',');
//loop through each category.
//hide every category and it's children
$("[data-token]").hide();
$.each(tokenValues, function (index, value) {
//show every category, and it's childen, for the values
$("[data-token='" + value + "']").show();
});
}
//excludeOnly is present?
if (ReadCookie(token_code[1]).toString().length > 0) {
//defines what the user wants to do. Exlcude or include? when token_code[0] it's include!
asc = token_code[1];
var tokens = ReadCookie(asc).toString();
tokenValues = decodeURIComponent(tokens).split(',');
//loop through each category.
//hide every category and it's children
$("[data-token]").show();
$.each(tokenValues, function (index, value) {
//show every category, and it's childen, for the values
$("[data-token='" + value + "']").hide();
});
}
is there an easier way to do this?
In the bottom of your code, were the comment says to show, it runs .hide().
Could that be a problem?
//show every category, and it's childen, for the values
$("[data-token='" + value + "']").hide();

Custom JQuery dynamic link creation

I'm pretty new to js and having a hard time figuring out the best way to generate a custom url depending on what links are selected. You can view what I have done here. http://jsfiddle.net/1fz50z1y/26/ I will also paste my info here.
var products = [];
var quantity = [];
qstring = '';
$('input.product-radio, select.products-howmany').change(function() {
var $this = $(this)
var $product = $(this).closest('.product-options-left');
var $radio = $product.find('input.product-radio');
var $select = $product.find('select.products-howmany')
var qid = $select.val();
var pid = $radio.val();
currentStatus = $radio.prop('checked'),
theString = '';
qString = '';
pString = '';
if (currentStatus) {
products.push(pid);
quantity.push(qid);
if ($product.find('div.quantity').removeClass('q-hidden')) {
//code
}
} else {
products.splice(products.indexOf(pid), 1);
quantity.splice(quantity.indexOf(qid), 1);
$product.find('div.quantity').addClass('q-hidden');
}
if ((products.length > -1) || (quantity.length > -1)) {
if ((products.length === 0) || (quantity.length === 0)) {
console.log("Q Length: " + quantity.length);
pString += products[0];
qString += quantity[0];
console.log("qString = " + quantity);
} else {
pString = products.join('-p');
qString = quantity.join('_q');
if (quantity.length > 1) {
qString = quantity.splice(quantity.indexOf(qid), 1);
pString = products.splice(products.indexOf(pid), 1);
}
console.log("+ Q Length: " + quantity.length);
console.log("ADDING " + "p" + pString + "_q" + qString);
}
if ((qString == 'undefined') || (pString == 'undefined')) {
$('a.options-cart').prop("href", "#");
} else {
//$('a.options-cart').prop("href", "/cart/add/p" + theString + "_q" + qstring + "?destination=/cart");
//$('a.options-cart').prop("href", "/cart/add/p" + theString + "?destination=/cart");
$('a.options-cart').prop("href", "/cart/add/p" + pString + "_q" + qString + "?destination=/cart");
}
}
});
$('a.options-cart').click(function() {
alert(qstring);
var $this = $(this);
href = $this.attr('href');
if (href == '#') {
alert("You must select a product.");
return false;
}
});
When you click on the add link icon it displays a drop down where you can select the quantity. So changing the quantity should also update the link and how it is created. I am trying to figure out how to create the link so the end result looks like so.
cart/add/p123_q1?destination=/cart this is how it would look with a single item. Where p = the product ID and q = the quantity. Unclicking the add to cart should remove those items and changing the drop down should update the quantity. If there is more than one item it should append to the link like so. cart/add/p123_q1-p234_q2-p232_q4?destination=/cart and then unclicking or changing quantity on any of those items should reflect the change in the link. I am not sure if I am going about this all wrong but I have been trying forever and many different routes to go about trying to achieve this effect. If anyone could please help me figure this out I would be greatly appreciated!
I was able to get this to work properly using this piece of code. Hope this maybe helps someone.
$('input.product-radio, select.products-howmany').change(function () {
var $product = $(this).closest('.product-options-left');
var $radio = $product.find('input.product-radio');
var $select = $product.find('select.products-howmany')
$product.find('div.quantity').toggleClass('q-hidden', !$radio.prop('checked'));
$product.find('label.quantity').toggleClass('q-hidden', !$radio.prop('checked'));
var string = $('.product-radio')
.filter(':checked')
.map(function(){
return $(this)
.closest('.product-options-left')
.find('.products-howmany')
.val();
})
.get()
.join('-');
$('a.options-cart').prop("href", "/cart/add/" + string + "?destination=/cart");
});
$('a.options-cart').click(function() {
alert(qstring);
var $this = $(this);
href = $this.attr('href');
if (href == '#') {
alert("You must select a product.");
return false;
}
});

converting javascript array into html table in new window on click

I am creating data visualizations, and I have a button that will execute a JavaScript function and extract the first five rows from specified columns of data based on the user's selection:
getselection.onclick = function()
{
visual.Document.selection.getselection(
"City", \\identifies the selection
"Users", \\identifies the table
["Name", "Phone", "Zipcode"], \\identifies the columns
5,
function(args)
{
log(dump(args, "visual.Document.selection.getselection", 2));
});
};
The resulting output looks like this:
[Name]
0: xxxxx
1: xxxxx
2: xxxxx
[Phone]
0: xxxxx
1: xxxxx
What I would like to do is to display the results of the users selection in an HTML table in a new window that opens upon click. I have seen a suggestions for doing something similar to this, but for some reason I can't seem to get them to work. Here is what I have so far:
function getSelMarking() {
visual.Document.selection.getMarking(
"city",
"Users",
["Name", "phone", "Zipcode"],
5,
function(args) {
var UserIDs=dump(args);
HTMLstring='<HTML>\n';
HTMLstring+='<HEAD>\n';
HTMLstring+='<TITLE>New Document</TITLE>\n';
HTMLstring+='</HEAD>\n';
HTMLstring+='<BODY>\n';
HTMLstring+='<P>Hello World</P>\n';
HTMLstring+='<table>\n';
HTMLstring+='<tr>\n';
HTMLstring+='<td>'+UserIDs+'</td>\n';
HTMLstring+='<td>'+UserIDs+'</td>\n';
HTMLstring+='<td>'+UserIDs+'</td>\n';
HTMLstring+='</tr>\n';
HTMLstring+='</table>\n';
HTMLstring+='</BODY>\n';
HTMLstring+='</HTML>';
newwindow=window.open();
newdocument=newwindow.document;
newdocument.write(HTMLstring);
newdocument.close();
}
);
}
Thats as far as I've gotten. I am completely stuck on this - maybe I just don't have a good understanding of how the functions work? Regardless, thank you to anyone who can lend any type of assistance here.
i forgot to include the breakdown of the dump() function:
var dump = function(obj, name, indent, depth) {
if (depth > MAX_DUMP_DEPTH) {
return indent + name + ": <Maximum Depth Reached>\n";
}
if (typeof(obj) == "object") {
var child = null;
var output = name + "\n";
indent += "\t";
for (var item in obj) {
try {
if (item.charAt(0) == '_') {
continue;
}
child = obj[item];
} catch (e) {
child = "<Unable to Evaluate>";
}
if (typeof child == "object") {
output += dump(child, item, indent, depth + 1);
} else if (typeof(child) == "function") {
var functionName = String(child);
functionName = functionName.substring(0, functionName.indexOf("{", 0) -
10}
output += "\t" + item + ": " + functionName + "\n";
} else {
var value = "";
if (child == null) {
value = "[null]";
} else {
value = child;
}
output += "\t" + item + ": " + value + "\n";
}
}
return output + "\n";
} else {
return obj;
}
};
I found the answer to my own question. the difficulty here was caused my lack of understanding as to how javascript handled arrays. sorry everyone.

Using yepnope, how can I know if a css resource was loaded successfully?

I'm developping a webapp for internal use in a company with a strict (and evolving) firewall.
I'm using yepnope.js / Modernizr.load to load js and css files from CDN with fallbacks.
But how do I know if a css was loaded successfully ? Is there a way to test successful loading and activation of a css ?
Thanks to the hint from #Morpheus, here is a solution :
First, in order to not depend on anything (jQuery, etc.) we need to define 2 functions :
One to get the css property of an element :
from http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
function getStyle(oElm, strCssRule) {
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle){
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
else if(oElm.currentStyle){
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
}
return strValue;
},
Another to create an hidden DOM element and test its css properties :
from https://stackoverflow.com/a/8122005/587407
function test_css(element_name, element_classes, expected_styles, rsrc_name, callback) {
// create an element of given type
var elem = document.createElement(element_name);
// immediately hide it
elem.style.display = 'none';
// give it the class(es)
for (var i = 0; i < element_classes.length; i++) {
elem.className = elem.className + " " + element_classes[i];
}
// and add it to the DOM
document.body.appendChild(elem);
// test the given properties
// it happens (~1/3 times in local)
// that the css takes a few ms to apply.
// so we need a function that we can try directly first
// and retry again later in case of failure
var handle = -1;
var try_count = 0;
var test_function = function() {
var match = true; // so far
try_count++;
for (var key in expected_styles) {
console.log("[CSS loader] testing " + rsrc_name + " css : " + key + " = '" + expected_styles[key] + "', actual = '" + get_style_of_element(elem, key) + "'");
if(get_style_of_element(elem, key) === expected_styles[key]) {
match = match && true;
} else {
console.error("[CSS loader] css " + rsrc_name + " test failed (not ready yet ?) : " + key + " = " + expected_styles[key] + ", actual = " + get_style_of_element(elem, key) );
match = false;
}
}
if (match === true || try_count >= 3) {
if (handle >= 0)
window.clearTimeout(handle);
// remove our test element from the DOM
document.body.removeChild(elem);
if (!match)
console.error("[CSS loader] giving up on css " + rsrc_name + "..." );
else
console.log("[CSS loader] css " + rsrc_name + " load success !" );
callback(rsrc_name, match);
}
return match;
}
// use and program the function
if(! test_function() ) {
console.info("" + rsrc_name + " css test failed, programming a retry...");
handle = window.setInterval(test_function, 100);
}
}
Note that the previous function is tricky because of the delayed loading of css.
We can now use yepnope like this :
{
load: { 'bootstrap-css': 'http//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css' },
callback: function (url, result, key) {
// here for bootstrap, I test presence of .span1 class
test_css('span', [ 'span1' ], { 'width': '60px' }, function(match) {
if( match ) {
// it worked !
}
else {
// ... fallback on another CDN or local rsrc...
}
}
}

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