Remove parent and all child elements not working - javascript

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.

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!

Add hanging indent to CKEditor on web page [duplicate]

I'm using CKEditor and I want to indent just the first line of the paragraph. What I've done before is click "Source" and edit the <p> style to include text-indent:12.7mm;, but when I click "Source" again to go back to the normal editor, my changes are gone and I have no idea why.
My preference would be to create a custom toolbar button, but I'm not sure how to do so or where to edit so that clicking a custom button would edit the <p> with the style attribute I want it to have.
Depending on which version of CKE you use, your changes most likely disappear because ether the style attribute or the text-indent style is not allowed in the content. This is due to the Allowed Content Filter feature of CKEditor, read more here: http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
Like Ervald said in the comments, you can also use CSS to do this without adding the code manually - however, your targeting options are limited. Either you have to target all paragraphs or add an id or class property to your paragraph(s) and target that. Or if you use a selector like :first-child you are restricted to always having the first element indented only (which might be what you want, I don't know :D).
To use CSS like that, you have to add the relevant code to contents.css, which is the CSS file used in the Editor contents and also you have to include it wherever you output the Editor contents.
In my opinion the best solution would indeed be making a plugin that places an icon on the toolbar and that button, when clicked, would add or remove a class like "indentMePlease" to the currently active paragraph. Developing said plugin is quite simple and well documented, see the excellent example at http://docs.ckeditor.com/#!/guide/plugin_sdk_sample_1 - if you need more info or have questions about that, ask in the comments :)
If you do do that, you again need to add the "indentMePlease" style implementation in contents.css and the output page.
I've got a way to indent the first line without using style, because I'm using iReport to generate automatic reports. Jasper does not understand styles. So I assign by jQuery an onkeydown method to the main iframe of CKEditor 4.6 and I check the TAB and Shift key to do and undo the first line indentation.
// TAB
$(document).ready(function(){
startTab();
});
function startTab() {
setTimeout(function(){
var $iframe_document;
var $iframe;
$iframe_document = $('.cke_wysiwyg_frame').contents();
$iframe = $iframe_document.find('body');
$iframe.keydown(function(e){
event_onkeydown(e);
});
},300);
}
function event_onkeydown(event){
if(event.keyCode===9) { // key tab
event.preventDefault();
setTimeout(function(){
var editor = CKEDITOR.instances['editor1'], //get your CKEDITOR instance here
range = editor.getSelection().getRanges()[0],
startNode = range.startContainer,
element = startNode.$,
parent;
if(element.parentNode.tagName != 'BODY') // If you take an inner element of the paragraph, get the parentNode (P)
parent = element.parentNode;
else // If it takes BODY as parentNode, it updates the inner element
parent = element;
if(event.shiftKey) { // reverse tab
var res = parent.innerHTML.toString().split(' ');
var aux = [];
var count_space = 0;
for(var i=0;i<res.length;i++) {
// console.log(res[i]);
if(res[i] == "")
count_space++;
if(count_space > 8 || res[i] != "") {
if(!count_space > 8)
count_space = 9;
aux.push(res[i]);
}
}
parent.innerHTML = aux.join(' ');
}
else { // tab
var spaces = " ";
parent.innerHTML = spaces + parent.innerHTML;
}
},200);
}
}

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

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.

Toggle display:none to all tags in JavaScript (no jQuery) without classes : is it possible?

I've read similar posts but i only found where it says to add class to the HTML to do what i want, so, basically i have a button, that when i want to click it hides ALL code HTML tags, and when i click it again it shows them. Since i have a lot of code tags in a page it would take me quite a lot to add a class to each one. I've been trying a few things such as
if(document.getElementsByTagName("CODE").style.display === "block"){
document.getElementsByTagName("CODE").style.display = "none"
}
and something around that, all similar code, but they all either made my browser crash or didn't work. My question is, is it really a MUST to use the class name and check for the class name of it's possible to compare, as i "did" above in the code here, the display content of all tags? ( maybe looping with a for loop each element, i tried that too, with no result. )
i tried every possible thing with my few knowledge so far ( im still studying javascript ). I would really like to know if i am trying to do something really advanced or i just dont see how it can be done.
Thanks, i hope there wasnt another question like this, i've read all of the ones suggested and none ( except one it said to use class ) was like this.
They all recommend to add classes, so i feel like im trying to do something really impossible. Im not into jQuery yet, so dont talk about it please, thanks. ( first i must learn for good JavaScript )
You have to iterate through the results of document.getElementsByTagName("CODE"), it is an array-like variable. It is a jQuery feature that lets you write .css() to a list of objects and have them all processed. You need something like
ar = document.getElementsByTagName("code");
for (i = 0; i < ar.length; ++i)
ar[i].style.display = "none";
If you need to toggle code visibility, use this code
ar = document.getElementsByTagName("code");
for (i = 0; i < ar.length; ++i)
{
if(ar[i].style.display != "none") //the element is visible
{
ar[i].style.display = "none";
}
else
{
ar[i].style.display = "block"; //If you need to make it block explicitly, otherwise ""
}
}
Note that the style.display property is initially empty and defaults to inline for code tag but can be set explicitly to other values. Resetting it to '' results in restoring the state.
If you need to change the visibility back and forth without the modification of display mode, you need to save the previous mode (code tags can be displayed not only in block mode). Can be done like this:
ar = document.getElementsByTagName("code");
for (i = 0; i < ar.length; ++i)
{
if(ar[i].style.display != "none") //the element is visible, "" or "blocK" or some other value
{
ar[i].saved_display = ar[i].style.display; //Save the display mode to a new property of the tag
ar[i].style.display = "none"; //And hide the element
}
else
{
if (typeof ar[i].saved_display === "undefined") //It's the first time we see the element. Display it in default mode
ar[i].style.display = "";
else
ar[i].style.display = ar[i].saved_display; //We know how the element was shown before we hid it, restoring
}
}
As Aneri says, getElementsByTagName returns a NodeList that you can iterate over by index.
Note that the display property only has a value if it's been explicitly set, it does not inherit a value from CSS so you should do something like the following, which will hide all the CODE elements if their display hasn't been set to none and display them if it has:
var element, elements = document.getElementsByTagName("CODE");
for (var i=0, iLen=elements.length; i<iLen; i++) {
element = elements[i];
// If element hasn't been hidden, hide it
if (element.style.display == '') {
element.style.display = 'none';
// Otherwise show it
} else {
element.style.display = '';
}
}
Note that you should return the display value to "" (empty string) so that the elements return to their default or inherited value, which might not be "block".
Also, child elements will be hidden if their parent element has display: none.
You can add a class just to BODY or HTML element and attach needed styles to this class via e.g. context selectors. For example:
HTML.hide-code CODE {display: none; }

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.

Categories

Resources