How to set style of element loaded into <object> as data - javascript

I've recently inherited some code that I need to maintain, part of which is a web-app meant to be used on iPad.
Unfortunately, the recent iOS 8 update broke a part of said web-app.
In one section, the web-app contained an iframe which loaded in a list of items. This iframe used to scroll with only one finger when run as a web-app, but now only scrolls with two fingers. * The one finger vs. two finger scrolling of iframe content in iOS web-apps is a whole other can of worms, and NOT what I'm looking for help with though * - I need help with implementing my solution.
If I place the content in a div I can get it to scroll as I want, however, I then also have to use an object to load in the content (coming from a separate page) - this is where my jQuery problem arises.
When an item is selected from the loaded list it is highlighted - once the user is finished and his/her selections are submitted the "highlighted" items are then "deselected" using jQuery to remove the "highlighted" style.
This worked fine with the iframe, but I can't manage to change the styling of the items now that they are contained within a div and object.
Here are some code snippets to illustrate what's going on:
ORIGINAL (works correctly with iframe)
<iframe id="myiframe" src="item_list.html"></iframe>
<script>
function deselect()
{
var itemcount = $('#ItemCount').val();
for (var i = 0; i < itemcount; i++) {
// item ids are named a1, a2, a3, etc.
$("#myiframe").contents().find("#a" + i).css("font-size", "26px");
$("#myiframe").contents().find("#a" + i).css("font-weight", "normal");
$("#myiframe").contents().find("#a" + i).css("color", "#3A3B3B");
}
}
</script>
MY ATTEMPT (not working)
<div id="myiframe">
<object id="myloader" type="text/html" data="item_list.html" ></object>
</div>
<script>
function deselect()
{
var itemcount = $('#ItemCount').val();
for (var i = 0; i < itemcount; i++) {
// item ids are named a1, a2, a3, etc.
//doesn't work - I think contents() is specifically for iframes?
$("#myiframe, #myloader").contents().find("#a" + i).css("font-size", "26px");
// none of these work
var path = "#myiframe, #myloader, #a" + i ;
var path = "#myiframe, #a" + i ;
var path = "#myloader, #a" + i ;
var path = "#a" + i ;
$(path).css("font-size", "26px");
// none of these work
var path = "#myiframe, #myloader" ;
var path = "#myiframe" ;
var path = "#myloader" ;
$(path).find("#a" + i).css("font-size", "26px");
// someone suggested using data() but it didn't work for me
// either AND I don't think that that's how it's used anyhow
}
}
</script>
Admittedly, I'm not really a jQuery guy, but this seems like it should be fairly easy...
Thanks in advance for any help you can offer.

Even though I think it's better to use ajax to load the content into a div (and a single DOM), I found a way to access the document within the <object> element.
$("#a0", $("#myloader")[0].contentDocument) will select the a0 element in the document held within the object data.
The second parameter to the jquery selection is the context in which to search, $("#myloader)[0] returns the HTMLObjectElement (and is equivalent to document.getElementById('myloader'), and contentDocument returns the HTML document retrieved via data attribute.
function deselect()
{
var itemcount = $('#ItemCount').val();
for (var i = 0; i < itemcount; i++) {
// item ids are named a1, a2, a3, etc.
//searches the content document within the object tag
$("#a"+i, $("#myloader")[0].contentDocument).css("font-size", "26px");
// I still think you should use .addClass() and .removeClass()
// (or data attributes if you want to be super fancy),
// changing the styles with CSS,
// rather than manipulate the styles directly in javascript.
}
}

Is there a reason for using an <object> element? Jquery has a method .load() which will request and insert the returned data/html into an element. http://api.jquery.com/load/
<div id="myiframe">
<div id="myloader"></div>
</div>
Then you would load the data:
<script type='text/javascript'>
$(function() {
$('#myloader').load("item_list.html", function() {
//at this point, the elements are in the document:
$('#a0').css("font-size", "26px");
//...
});
});
function deselect() {
var itemcount = $('#ItemCount').val();
for (var i = 0; i < itemcount; i++) {
$('#a'+i).css("font-size", "26px");
//etc.
}
}
</script>
I would add that instead of manually editing the css in javascript, you use jquery to .addClass(), removeClass(), or .toggleClass() css classes which contain the styling you are looking for.

Related

Loop through a list of Elements by Partial Link Text Selenium

I'm stuck and need help on investigation and improvement.
I am trying to gather all the <a> tags with Annual Report as their partial text then loop through them since they're originally located inside a table(2nd column per row).
Below is the process that I'm planning to execute:
After clicking an <a> tag, a new window would pop up
find and get specific values in the new window
close the window
move to the next element (<a> tag) and repeat
The code below is my current progress, but it is completely not working. I am still unable to click the very first element.
var reportLinks = driver.findElements(By.partialLinkText('Annual Report'));
for(var i = 0; i < reportLinks.length; i++){
reportLinks[i].click();
}
This is how I would accomplish this
//This will get you how many elements are present
var reportLinks = driver.findElements(By.xpath('//tr/td/a[contains(text(),'Annual Report')]'));
//This will click on each element
for(var i = 0; i < reportLinks.length; i++){
driver.findElement(By.xpath('//tr[' + i + ']/td/a[contains(text(),'Annual Report')]')).click();
}
The reason for this is the Annual Report element is not the parent container the element is.
I was able to make it work using the code below:
for (var i = 1; i < 51; i++) {
var element = driver.findElement(By.xpath('//*[#id="dataList"]/table/tbody/tr[' + i + ']/td[1]/a'));
driver.executeScript("arguments[0].click();", element);
}
I just copied the xpath on the page through Google Chrome's Inspect Element feature and passed an argument via executeScript.
You could find out how via this link: Is there a way to get the xpath in google chrome?
Thank you very much!

Remove parent and all child elements not working

I am developing a plugin for my own usage, and I want to get rid of all the annoying wordpress messages that appear on top including updates, errors, info, etc. Given the obvious fact that the plugin's menu page is generated by php, I tried removing these messages with a php code which according to my research is this:
function remove_core_updates(){
global $wp_version;return(object) array('last_checked'=> time(),'version_checked'=> $wp_version,);
}
add_filter('pre_site_transient_update_core','remove_core_updates');
add_filter('pre_site_transient_update_plugins','remove_core_updates');
add_filter('pre_site_transient_update_themes','remove_core_updates');
I added this at the top of my plugin php file and should remove the notifications, but the error message for some plugins still appear. Apart from this, the code above removes the update notification for all menu pages I access in my dashboard. This I do not want.
As a workaround, I wrote a function which does what I want:
function remove_wp_messages(selector) {
var child = document.querySelector(selector),
parent = child.parentNode,
index = Array.prototype.indexOf.call(parent.children, child);
for (var i = 1; i < Number(index + 1); i++) {
var elements = document.querySelector("#wpbody-content > :nth-child(" + i + ")");
while (elements.firstChild) {
elements.removeChild(elements.firstChild);
elements.style.display = "none";
}
}
}
window.onload = remove_wp_messages("#wpbody-content > link");
Given that the first html element I add to the menu page is a link to an external stylesheet, the javascript function above returns the index of that link and removes all child nodes from the elements up to the link, hence the loop. Here is the issue, I want to not only remove the child elements but the parents as well which would be equivalent to removing the notifications above the content of my plugin. I tried replacing:
elements.style.display = "none";
With this:
elements.remove();
No luck. What I do not understand is, that the parent elements get hidden, but I replace it with remove() it removes my content instead of the notifications. Why? I am open to both php and javascript suggestions.
SOLUTION
According to #PetrSr answer, my code now looks like this:
function remove_wp_messages(selector) {
var child = document.querySelector(selector),
parent = child.parentNode,
index = Array.prototype.indexOf.call(parent.children, child);
for (var i = Number(index); i > 0; i--) {
document.querySelector("#wpbody-content > :nth-child(" + i + ")").remove();
}
}
Pretty straightforward.
Looping through the elements backwards like this should fix your issue:
for (var i = Number(index); i > 0; i--) {
//your code
}
You cannot loop forward when removing DOM elements the way you did, because after removing element1, element2 becomes the first one. If you then remove the second element, you are in fact removing what was originally element3. Etc.

changing cssRules with javascript is not permanent on client, getting wiped out after partial post back

I generated some css from database values on Page_Load and Then wrapped it like-
CssDiv.InnerHtml = "<style id=\"main_styles\" type=\"text/css\">\n" + {Css as string} + "\n</style>"
here CssDiv is like-
<div id="CssDiv" runat="server"></div>
user are allowed to change these css values with color pickers and drop downs. on change of picker or dropdown, I am making ajax call with the selected value to server, saving it into database. Now on success of this request, I have to change the content of $("style#main_styles") according to user's selection.
The problem is
1) When I am changing the Css its being reflected on the page but not under developer tool (that open when you right click to Inspect element). For example assume following css-
#zoneBody .blocktextContent {
background-color: #99daee;
}
now user selected #1066cc from the picker, when my code runs #1066cc is being applied on the element "#zoneBody .blocktextContent" on page but when I am inspecting the element in the developer console its still showing-
#zoneBody .blocktextContent {
background-color: #99daee; // while it should be- "background-color: #1066cc;"
}
2) The changes I made are not permanent on browser, i.e. when any other element on Page is causing partial post-back, although I am not touching CssDiv on server yet its resetting the users selection.
(I have an update panel, that wraps complete page content, even CssDiv... This is causing partial post-backs).
I am using following code to apply the user's selection-
var layoutelement= "#zoneBody .blocktextContent";
var style = "background-color";
var stylevalue= "#1066cc"; // user's selection
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
var sheet = sheets[i];
if (sheet.ownerNode.id == "main_styles") {
var rules = sheet.cssRules;
for (var j = 0; j < rules.length; j++) {
var rule = rules[j];
if (rule.selectorText == layoutelement) {
rule.style.setProperty(style, stylevalue);
// I also tried "rule.style[style] = stylevalue;"
break;
}
}
break;
}
}
I can not use-
$(layoutelement).css(style, stylevalue);
because layoutelement can be more complex like-
layoutelement = "#zoneBody .blockTextContent a,#zoneBody .blockTextContent a:link,#zoneBody .blockTextContent a:visited,#zoneBody .blockTextContent a .yshortcuts";
I hope I am clear enough, but if you need any more description.. let me know in comments.. Thank you
Instead of changing the values of the styles, why not write the styles down in advance, and just toggle the element's classes? You can use jQuery addClass, removeClass and toggleClass if you want. Much more practical than fiddling with the CSS style definitions themselves.
For problem 1, the issue is probably that the developer tool (or view within the developer tool) you are using does not show applied styles, but simply the rules in the style sheet that match that element based on the selector. Or, in other words, it only shows the css rules in the style sheet that apply to the element you are inspecting. To see the styles that are applied at a given time, you will need to examine the styles by inspecting the element in the DOM or use javascript and the CSSStyleDeclaration object returned by getComputedStyle.

Jquery dynamic list generation

for(var i=0; i< vendors.length;i++)
{
var $ul = $("<ul>").attr("data-role", "listview")
.attr("data-divider-theme","a")
.attr("data-inset","true")
.appendTo("#vendorLists");
$("<li>").attr("data-role", "list-divider")
.attr("role","heading")
.text(vendors[i])
.appendTo($ul);
for(var j=0; j<coupons[i].length; j++)
{
var x = coupons[i][j].split(":");
var $li = $("<li>").attr("data-theme", "a")
.appendTo($ul);
$("<a>").text(x[0] + ":" + x[1])
.appendTo($li);
}
}
I am using this code to create a list dynamically by fetching from a array.
vendorList is a div tag
The Jquery isnt coming on these..only the text is being displayed
Plz help
You mention vendorList is a div tag. However, you use appendTo("#vendorLists") in your definition of $ul. Unless you meant vendorLists is a div tag, then you want to use appendTo("#vendorList") instead.
Each time you add a dynamic content to the jQuery Mobile page you need to trigger a specific function meant to enhance page markup.
In your case it is this function:
$('[data-role="listview"]').trigger('refresh');
If you want to read more about that (with live jsFiddle examples) take a look at my other ARTICLE about this topic. Or it can be found HERE.

Javascript/Tumblr: add CSS class on condition (has to be JS because Tumblr)

I'm very sorry but after a few hours of trying I just have to ask the experts :)
I've got the following code in my Tumblr theme:
{block:Photo}
<li class="post photo">
// Retrieving photo url here using {PhotoURL-500}.
{/block:Photo}
This retrieves all photo posts and displays them on a page.
Now I want to give the li a class, depending on the image orientation. I've retrieved this by using:
<script type="text/javascript">
var width = {PhotoWidth-500}; // this is a Tumblr variable that gets the width
var height = {PhotoHeight-500}; // this is a Tumblr variable that gets the height
if (width > height) {
// Here I get stuck, I want to append class="horizontal" to the li above.
}
else {
// append class="vertical"
}
</script>
I do have to call the javascript inside the {block:Photo} though, as otherwise I cannot determine each photo's individual height and width. And as a reminder; I'd love to do this in PHP and just echo it, but Tumblr does not allow that. And I'm a JS noob...
Help would be much appreciated! Thanks in advance!
On any modern browser, you can use querySelectorAll to get a NodeList of elements matching a selector, e.g.
var list = querySelectorAll(".post.photo");
...and then loop through them appending to their className property. E.g.:
var list = querySelectorAll(".post.photo"),
index,
node;
for (index = 0; index < list.length; ++index) {
node = list[index];
if (some_condition) {
node.className += " theNewClassToAdd";
}
}
If you need to support older browsers, getElementsByClassName has been around for a long time (but I believe it only supports querying by a single class, so you'd have to post-process to make sure both classes existed).
Or for broadest support, leverage the work of others by using a decent library like jQuery, YUI, Closure, or any of several others.

Categories

Resources