My HTML is:
<a id="showSlotsByLocation_" href="#" style="color:blue;" onclick="confirmAppt('28/05/2013','364301');">14.00 - 14.15</a>
<a id="showSlotsByLocation_" href="#" style="color:blue;" onclick="confirmAppt('28/05/2013','364303');">14.15 - 14.30</a>
Id name are same on all links. This is the main difficulty.
I want to click second link my javascript code are configure web browser is
if (location.pathname == "/abc")
{
//alert('location found') this is ok found;
var el = document.getElementsByTagName("a");
for (var i=0;i<el.length;i++)
{
if (el.id == 'showSlotsByLocation_' && el.innerText.isEqual('14.15 - 14.30') && el.outerHTML.contains("confirmAppt('28/05/2013'"))
{
alert('link found') \\this condition not match;
el.onclick();
}
}
}
What do i do to match the condition?
You can't have two element with the same ID, IDs are unique.
When you will have changed the IDs, you'll can access them simply using document.getElementById('idOfYourElement')
EDIT:
First of all, you need to declare a "current" variable that takes the current element in the loop, you can't use el.id because el is a collection of HTMLElements! I'm sorry I didn't noticed it before.
So you need this(define the variable inside the for loop, just before the if statement):
var current = el[i];
Now that you have defined it, change this whole line with the code below.
if (el.id == 'showSlotsByLocation_' && el.innerText.isEqual('14.15 - 14.30') && el.outerHTML.contains("confirmAppt('28/05/2013'"))
I think this is the code that stops you. There are no functions called isEqual and contains in JS.
if (current.id == 'showSlotsByLocation_' && current.textContent === '14.15 - 14.30' && current.outerHTML.indexOf("confirmAppt('28/05/2013'") !== -1)
One last thing: innerText isn't a valid cross browser property, use textContent instead.
MDN Reference
Updated JS code
if (location.pathname == "/abc")
{
var el = document.getElementsByTagName("a");
for (var i=0;i<el.length;i++)
{
var current = el[i];
if (current.id == 'showSlotsByLocation_' && current.textContent === '14.15 - 14.30')//I'm not sure about this one, in case you want it just remove the comment and the last parenthesis && current.outerHTML.indexOf("confirmAppt('28/05/2013'") !== -1)
{
alert('link found');
current.click();
}
}
}
Related
I am trying to cycle through a list of custom autocomplete options using the arrow keys in JavaScript. I am attempting to do this by iterating through the options and adding a "selected" ID to the option currently selected. I've run in to a problem where, although the "selected" ID of the option currently selected is visible (if you log it out, you can see the ID), the ID is inaccessible (trying to log out element.id returns an empty string).
Here is the code:
SearchBox.prototype.handleOptionNavigation = function() {
_this.inputElement.addEventListener("keyup", function(event) {
var options = _this.getOptions();
if (event.key === "ArrowUp") _this.moveSelectedUp();
if (event.key === "ArrowDown") _this.moveSelectedDown();
});
}
SearchBox.prototype.getOptions = function() {
return Array.from(document.getElementsByClassName("result-item"));
}
SearchBox.prototype.getSelectedIndex = function() { //here is the problem
var options = _this.getOptions();
if (options.length === 0) return;
console.log(options[2]);
//this returns <li class="result-item" id="selected">...</li>
console.log(options[2].id);
//this returns an empty string
return 1;
//this function is supposed to return the index of the element currently selected;
//I am returning 1 just to see a selected element on the screen.
}
SearchBox.prototype.moveSelectedDown = function() {
var options = _this.getOptions();
if (options.length === 0) return;
var selectedIndex = _this.getSelectedIndex();
if (selectedIndex === -1) {
options[0].id = "selected"
} else if (selectedIndex === (_this.maxResults - 1)) {
options[0].id = "selected"
options[options.length - 1].removeAttribute("id");
} else {
console.log("we are moving down");
options[selectedIndex + 1].id = "selected";
options[selectedIndex].removeAttribute("id");
}
}
SearchBox.prototype.moveSelectedUp = function() {
var options = _this.getOptions();
if (options.length === 0) return;
var selectedIndex = _this.getSelectedIndex();
console.log(selectedIndex);
if (selectedIndex === -1) {
options[options.length - 1].id = "selected";
} else if (selectedIndex === 0) {
options[0].removeAttribute("id");
} else {
options[selectedIndex - 1].id = "selected";
options[selectedIndex].removeAttribute("id");
}
}
The idea is that, with each press of the up or down arrows, a different element in the list of complete options will become highlighted. However, because I can't seem to access the id of the selected element, it gets stuck and the moveSelectedUp/moveSelectedDown functions don't work.
Does anyone know what is going on here?
Thank you!
Not quite sure what you are trying to achieve in your method SearchBox.prototype.getSelectedIndex, but it is always returning 1, how is that supposed to help ?
I've updated your method so that it returns the real index and it seems to work fine, see the fiddle below :
https://jsfiddle.net/c2p1aayh/
I have an array (spliced to size 2) that keeps track of what user click (first, last). first and last elements are unique.
I am trying to load content based on what user clicked. The weird thing that is happening is that I don't see the updated array unless I do 2 console.logs. If 1 log is done the array doesn't get updated. I'm guessing this has something to do with array execution/manipulation time.
The way I debug is to a click handler to document and click to see the array value. Any suggestions or tips?
I never had this issue before. Thanks.
var clicksInfo = [];
$('#a, #b, #c').on('click', function(e){
// array: add, splice
if(jQuery.inArray($(this).attr('id'), clicksInfo) == -1){
clicksInfo.push($(this).attr('id'));
if(clicksInfo.length == 2){
// might do something
}else if(clicksInfo.length == 3){
clicksInfo.splice(0,1);
}
}else{
clicksInfo.splice(0,1);
clicksInfo.push($(this).attr('id'));
}
if($(this).attr('id') == 'a'){
// do stuff.
}else if($(this).attr('id') == 'b'){
// do stuff.
}else if($(this).attr('id') == 'c'){
// do stuff.
}
});
$(document).on('click', function(){
console.log('clicksInfo', clicksInfo);
// console.log('clicksInfo', clicksInfo);
});
Strings are strings, arrays are arrays, even in a console.log, so when doing :
console.log('clicksInfo', clicksInfo);
thats a string, a comma, and then an array ?
try doing:
console.log('clicksInfo : '+ clicksInfo);
to show the string representation, or to show the array as an object, don't mix it with other strangeness:
console.log(clicksInfo);
The problem you are facing is that events that occur are not guaranteed to execute in a specific order. Either click handler could be executed first, though in most browsers your handler for #a, #b, #c would be executed first.
While you could try to use setTimeout to wait long enough to synchronize your data, your code is quite likely to break.
If you want to handle a click in both cases, my recommendation would be to remove the handler for #a, #b, and #c. Use the document click handler only, pass in the event declaration, and then check the ID of the clicked element in your handler to invoke the first code. You are then guaranteed to have updated data before your second block of code runs. Something like this:
var clicksInfo = [];
$(document).on('click', function(e){
if (e.target.id === "a" || e.target.id === "b" || e.target.id === "c") {
// array: add, splice
if (jQuery.inArray(e.target.id, clicksInfo) == -1){
clicksInfo.push(e.target.id);
if(clicksInfo.length == 2){
// might do something
} else if(clicksInfo.length == 3){
clicksInfo.splice(0,1);
}
} else {
clicksInfo.splice(0,1);
clicksInfo.push(e.target.id);
}
if(e.target.id === 'a'){
// do stuff.
}else if(e.target.id === 'b'){
// do stuff.
}else if(e.target.id === 'c'){
// do stuff.
}
}
console.log('clicksInfo', clicksInfo);
});
JSFiddle here.
I need to find all block elements in a given node. Block elements are not just elements that have display:block in the CSS, but also default block elements like div and p.
I know I can just get computed style of the element and check for the display property, however, my code will execute in a long loop and getting computed styles flushes reflow stack every time, so it will be very expansive.
I'm looking for some trick to do this without getComputedStyle.
Edit
Here's my current code that I would like to improve:
var isBlockOrLineBreak = function(node)
{
if (!node) {
return false;
}
var nodeType = node.nodeType;
return nodeType == 1 && (!inlineDisplayRegex.test(getComputedStyleProperty(node, "display")) || node.tagName === "BR")
|| nodeType == 9 || nodeType == 11;
};
Another edit
jQuery's .css calls getComputedStyle under the hood. So that's not what I'm looking for.
My solution
Thanks everyone for suggestions. Unfortunately, none of them matched what I was looking for. After a lot of digging through documentation I realized that there's no real way to do this without getComputedStyle. However, I came up with the code that should avoid getComputedStyle as much as humanly possible. Here's the code:
$.extend($.expr[':'], {
block: function(a) {
var tagNames = {
"ADDRESS": true,"BLOCKQUOTE": true,"CENTER": true,"DIR": true,"DIV": true,
"DL": true,"FIELDSET": true,"FORM": true,"H1": true,"H2": true,"H3": true,
"H4": true,"H5": true,"H6": true,"HR": true,"ISINDEX": true,"MENU": true,
"NOFRAMES": true,"NOSCRIPT": true,"OL": true,"P": true,"PRE": true,"TABLE": true,
"UL": true,"DD": true,"DT": true,"FRAMESET": true,"LI": true,"TBODY": true,
"TD": true,"TFOOT": true,"TH": true,"THEAD": true,"TR": true
};
return $(a).is(function() {
if (tagNames[this.tagName.toUpperCase()]) {
if (this.style.display === "block")
{
return true;
}
if (this.style.display !== "" || this.style.float !== "")
{
return false;
}
else {
return $(this).css("display") === "block";
}
}
else {
if (this.style.display === "block") {
return
}
else {
return $(this).css("display") === "block";
}
}
});
}
});
Usage of this code is very simple just do $(":block") or $("form :block"). This will avoid using .css property in a lot of cases, and only fallback to it as a last resort.
Starx's answer was what gave me the idea to do this, so I'm going to mark his message as an answer.
For the answer to this problem, we take into account the universal CSS selector and the jQuery .filter() function:
$("*").filter(function(index) {
return $(this).css("display") == 'block';
});
This code looks at all elements it can find, and it returns a list of elements if they pass a filter. The element passes a filter if the filter function returns true for that element. In this case, the filter tests the display property of each found element and tests it against the desired value.
Now, you also mentioned that you want to find p and div elements. Luckily, we also have a way to find these in the filter function. Using jQuery's prop function, we can return a property of an element. In this case, we are interested in the tagName property of the DOM elements being filtered. Combining this feature with the above filter, we get:
$("*").filter(function(index) {
var $this = $(this);
var tagName = $this.prop("tagName").toLowerCase();
return $this.css("display") == 'block' || tagName == 'p' || tagName == 'div';
});
Notice how we set the tagName variable to lowercase, because we cannot expect a certain case for the tagName property (correct me if I'm wrong).
The best way I see is to
assign a common class to all the not-native block element and
using jQuery's mulitple-selector.
Then we can do it as simple as this this
CSS:
.block { display: block; }
jQuery:
var blockelements = $("div, p, table, ..., .block");
// ^ represents other block tags
If you want to include all the block elements. Here is a link
maybe this helps.
$('*').each( function(){
if ($(this).css("display") === "block")
$(this).css("background", "yellow") ;
});
jsfiddle
I have the following html -
<a>
<b>
....
.....
<input type="button" name="add" onclick="..." value="add another"/>
</d>
</b>
....
</a>
And I use the following js snippets-
/**
* Dynamically add a remove button on next to the add button.
*
*/
addRemoveButton = function(node) {
if(node.nodeType == 3) {
if(node.nodeName == "input") {
if(node.getAttribute("type") == "button") {
if(node.getAttribute("name") == "add") {
var removeButton = node.cloneNode(true);
removeButton.removeAttribute("name");
removeButton.setAttribute("value", "remove");
removeButton.setAttribute("onclick", "");
removeButton.setAttribute("id", "");
(node.parentNode).appendChild(removeButton);
return;
}
}
}
}
if(node.nodeType == 1) {
var list = node.childNodes;
var i = 0;
while(i<list.length) {
return addRemoveButton(list[i]);
i++;
}
}
return;
}
Now I want to add a input of type button, (remove button), next to the current button shown in the above listing. I tried to do this recursively. But this is not working. Can you find the problem in the above code?
As far as I can tell, your code was pretty far off. You were using the wrong nodeType and had the wrong case on nodeName and there was no reason for the vastly nested if statements. But, you can make it work recursively like this:
addRemoveButton = function(node) {
if (node.nodeType == 1) {
if (node.nodeName.toLowerCase() == "input" &&
node.getAttribute("type") == "button" &&
node.getAttribute("name") == "add") {
var removeButton = node.cloneNode(true);
removeButton.removeAttribute("name");
removeButton.setAttribute("value", "remove");
removeButton.setAttribute("onclick", "");
removeButton.setAttribute("id", "");
(node.parentNode).appendChild(removeButton);
return;
} else {
var list = node.childNodes;
for (var i=0; i < list.length; i++) {
// be aware of childNodes changing on us live here
// when we modify the DOM
addRemoveButton(list[i]);
}
}
}
}
addRemoveButton(document.body);
You can see it work here: http://jsfiddle.net/jfriend00/WCj4b/
Using jQuery (which you also tagged your question with) and continuing to use the clone operation, you can do this:
$("input[type='button'][name='add']").each(function(index, el) {
$(this).clone(false)
.val("remove")
.removeAttr("name")
.attr("onclick", "")
.attr("id", "")
.insertAfter(this);
});
Demo here: http://jsfiddle.net/jfriend00/JKsZC/
Or a much, much simpler version that just inserts new HTML rather than clone the existing button:
$("input[type='button'][name='add']").after('<input type="button" value="Remove" />');
Demo here: http://jsfiddle.net/jfriend00/vSZwp/
Why recursive? Just to find the existing button? Let jQuery worry about finding it
$('input[type=button]').after("<input type='button' value='Remove' />");
Tweak this to get your remove button to do what you need.
I'm trying to transform a blog on blogger into a website. In order to have a static home page I am using the Javascript code below to see if the user is on the home page if they are then it will hide the post section and display a home page "gadget". Is anything supposed to match anything?
document.onload = hidepage();
function hidepage () {
if (window.location == "http://website.blogspot.com/" || window.location == "http://website.blogspot.com/?zx=" + ANYTHING) {
//Checks to see if user is on the home page
$(".hentry").hide(); //Hide posts
$(".hfeed").hide(); //Hide posts
}
else {
$("#HTML2").hide(); //hide gadget
}
$(".post-title").hide(); //Hide post titles
}
Based on what you're saying I think you want to change the if condition to:
if (window.location.href === "http://website.blogspot.com/" ||
window.location.href.indexOf("http://website.blogspot.com/?zx=") > -1)
You could also shorten this to:
if (window.location.href === "http://website.blogspot.com/" ||
window.location.href.indexOf("/?zx=") > -1)
Note that I've changed your == to === as the latter is a literal comparison.
Just use String.indexOf in the second half of the if expression.
var url = window.location.href;
if (url === "http://website.blogspot.com/" || url.indexOf("http://website.blogspot.com/?zx=") === 0) {
// do stuff
}