I need to get :after and assign it to variable. It is possible?
querySelectorAll doesn't work.
alert(some_div_with_pseudo.querySelectorAll('::after')[0]) // undefined
The short answer is that you can’t. It’s not there yet.
JavaScript has access to the DOM, which is built when the page is loaded from HTML, and modified further when JavaScript manipulates it.
A pseudo element is generated by CSS, rather than HTML or JavaScript. It is there purely to give CSS something to hang on to, but it all happens without JavaScript having any idea.
This is how it should be. In the overall scheme of things, the pages starts off as HTML. JavaScript can be used to modify its behaviour and to manipulate the content on one hand, and CSS can be used to control the presentation of the result:
HTML [→ JavaScript] → CSS → Result
You’ll see that CSS, complete with pseudo elements, comes at the end, so JavaScript doesn’t get a look in.
See also:
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector#Usage_notes
https://www.w3.org/TR/selectors-api/#grammar
Edit
It seems that in modern JavaScript there is a workaround using window.getComputedStyle(element,pseudoElement):
var element = document.querySelector(' … ');
var styles = window.getComputedStyle(element,':after')
var content = styles['content'];
You can do this:
window.getComputedStyle(
document.querySelector('somedivId'), ':after'
);
Sample here: https://jsfiddle.net/cfwmqbvn/
I use an arrow pointing in the direction that the content and sidebar will toggle to/from via a CSS pseudo-element. The code below is effectively a write mode however it is entirely possible to read CSS pseudo-element content as well.
Since there is a bit involved I'll also post the prerequisites (source: JAB Creations web platform JavaScript documentation, if anything missing look it up there) so those who wish to try it out can fairly quickly do so.
CSS
#menu a[href*='sidebar']::after {content: '\2192' !important;}
JavaScript Use
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');
JavaScript Prerequisites
var sidebar = 20;
function id_(id)
{
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
function css_rule_set(selector,property,value,important)
{
try
{
for (var i = 0; i<document.styleSheets.length; i++)
{
var ss = document.styleSheets[i];
var r = ss.cssRules ? ss.cssRules : ss.rules;
for (var j = 0; j<r.length; j++)
{
if (r[j].selectorText && r[j].selectorText==selector)
{
if (typeof important=='undefined') {r[j].style.setProperty(property,value);}
else {r[j].style.setProperty(property,value,'important');}
break;
}
}
}
}
catch(e) {if (e.name !== 'SecurityError') {console.log('Developer: '+e);}}
}
function sidebar_toggle()
{
if (id_('menu_mobile')) {id_('menu_mobile').checked = false;}
if (getComputedStyle(id_('side')).getPropertyValue('display') == 'none')
{
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');
if (is_mobile())
{
css_rule_set('main','display','none','important');
css_rule_set('#side','width','100%','important');
css_rule_set('#side','display','block','important');
}
else
{
css_rule_set('main','width',(100 - sidebar)+'%');
css_rule_set('#side','display','block');
}
}
else
{
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2190"','important');
if (is_mobile())
{
css_rule_set('main','display','block','important');
css_rule_set('main','width','100%','important');
css_rule_set('#side','display','none','important');
}
else
{
css_rule_set('main','width','100%','important');
css_rule_set('#side','display','none');
}
}
There is a way in JavaScript to access value of pseudo elements without any library. To get the value, you need to use the 'getComputedStyle' function. The second parameter is optional.
let elem = window.getComputedStyle(parent, ':before');
alert(elem.getPropertyValue('background'))
This will do alert the value of pseudo element.
let elem = window.getComputedStyle(document.querySelector('#item'), ':after');
console.log(elem.getPropertyValue('content'))
Related
I need to get :after and assign it to variable. It is possible?
querySelectorAll doesn't work.
alert(some_div_with_pseudo.querySelectorAll('::after')[0]) // undefined
The short answer is that you can’t. It’s not there yet.
JavaScript has access to the DOM, which is built when the page is loaded from HTML, and modified further when JavaScript manipulates it.
A pseudo element is generated by CSS, rather than HTML or JavaScript. It is there purely to give CSS something to hang on to, but it all happens without JavaScript having any idea.
This is how it should be. In the overall scheme of things, the pages starts off as HTML. JavaScript can be used to modify its behaviour and to manipulate the content on one hand, and CSS can be used to control the presentation of the result:
HTML [→ JavaScript] → CSS → Result
You’ll see that CSS, complete with pseudo elements, comes at the end, so JavaScript doesn’t get a look in.
See also:
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector#Usage_notes
https://www.w3.org/TR/selectors-api/#grammar
Edit
It seems that in modern JavaScript there is a workaround using window.getComputedStyle(element,pseudoElement):
var element = document.querySelector(' … ');
var styles = window.getComputedStyle(element,':after')
var content = styles['content'];
You can do this:
window.getComputedStyle(
document.querySelector('somedivId'), ':after'
);
Sample here: https://jsfiddle.net/cfwmqbvn/
I use an arrow pointing in the direction that the content and sidebar will toggle to/from via a CSS pseudo-element. The code below is effectively a write mode however it is entirely possible to read CSS pseudo-element content as well.
Since there is a bit involved I'll also post the prerequisites (source: JAB Creations web platform JavaScript documentation, if anything missing look it up there) so those who wish to try it out can fairly quickly do so.
CSS
#menu a[href*='sidebar']::after {content: '\2192' !important;}
JavaScript Use
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');
JavaScript Prerequisites
var sidebar = 20;
function id_(id)
{
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
function css_rule_set(selector,property,value,important)
{
try
{
for (var i = 0; i<document.styleSheets.length; i++)
{
var ss = document.styleSheets[i];
var r = ss.cssRules ? ss.cssRules : ss.rules;
for (var j = 0; j<r.length; j++)
{
if (r[j].selectorText && r[j].selectorText==selector)
{
if (typeof important=='undefined') {r[j].style.setProperty(property,value);}
else {r[j].style.setProperty(property,value,'important');}
break;
}
}
}
}
catch(e) {if (e.name !== 'SecurityError') {console.log('Developer: '+e);}}
}
function sidebar_toggle()
{
if (id_('menu_mobile')) {id_('menu_mobile').checked = false;}
if (getComputedStyle(id_('side')).getPropertyValue('display') == 'none')
{
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');
if (is_mobile())
{
css_rule_set('main','display','none','important');
css_rule_set('#side','width','100%','important');
css_rule_set('#side','display','block','important');
}
else
{
css_rule_set('main','width',(100 - sidebar)+'%');
css_rule_set('#side','display','block');
}
}
else
{
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2190"','important');
if (is_mobile())
{
css_rule_set('main','display','block','important');
css_rule_set('main','width','100%','important');
css_rule_set('#side','display','none','important');
}
else
{
css_rule_set('main','width','100%','important');
css_rule_set('#side','display','none');
}
}
There is a way in JavaScript to access value of pseudo elements without any library. To get the value, you need to use the 'getComputedStyle' function. The second parameter is optional.
let elem = window.getComputedStyle(parent, ':before');
alert(elem.getPropertyValue('background'))
This will do alert the value of pseudo element.
let elem = window.getComputedStyle(document.querySelector('#item'), ':after');
console.log(elem.getPropertyValue('content'))
I need to get :after and assign it to variable. It is possible?
querySelectorAll doesn't work.
alert(some_div_with_pseudo.querySelectorAll('::after')[0]) // undefined
The short answer is that you can’t. It’s not there yet.
JavaScript has access to the DOM, which is built when the page is loaded from HTML, and modified further when JavaScript manipulates it.
A pseudo element is generated by CSS, rather than HTML or JavaScript. It is there purely to give CSS something to hang on to, but it all happens without JavaScript having any idea.
This is how it should be. In the overall scheme of things, the pages starts off as HTML. JavaScript can be used to modify its behaviour and to manipulate the content on one hand, and CSS can be used to control the presentation of the result:
HTML [→ JavaScript] → CSS → Result
You’ll see that CSS, complete with pseudo elements, comes at the end, so JavaScript doesn’t get a look in.
See also:
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector#Usage_notes
https://www.w3.org/TR/selectors-api/#grammar
Edit
It seems that in modern JavaScript there is a workaround using window.getComputedStyle(element,pseudoElement):
var element = document.querySelector(' … ');
var styles = window.getComputedStyle(element,':after')
var content = styles['content'];
You can do this:
window.getComputedStyle(
document.querySelector('somedivId'), ':after'
);
Sample here: https://jsfiddle.net/cfwmqbvn/
I use an arrow pointing in the direction that the content and sidebar will toggle to/from via a CSS pseudo-element. The code below is effectively a write mode however it is entirely possible to read CSS pseudo-element content as well.
Since there is a bit involved I'll also post the prerequisites (source: JAB Creations web platform JavaScript documentation, if anything missing look it up there) so those who wish to try it out can fairly quickly do so.
CSS
#menu a[href*='sidebar']::after {content: '\2192' !important;}
JavaScript Use
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');
JavaScript Prerequisites
var sidebar = 20;
function id_(id)
{
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
function css_rule_set(selector,property,value,important)
{
try
{
for (var i = 0; i<document.styleSheets.length; i++)
{
var ss = document.styleSheets[i];
var r = ss.cssRules ? ss.cssRules : ss.rules;
for (var j = 0; j<r.length; j++)
{
if (r[j].selectorText && r[j].selectorText==selector)
{
if (typeof important=='undefined') {r[j].style.setProperty(property,value);}
else {r[j].style.setProperty(property,value,'important');}
break;
}
}
}
}
catch(e) {if (e.name !== 'SecurityError') {console.log('Developer: '+e);}}
}
function sidebar_toggle()
{
if (id_('menu_mobile')) {id_('menu_mobile').checked = false;}
if (getComputedStyle(id_('side')).getPropertyValue('display') == 'none')
{
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2192"','important');
if (is_mobile())
{
css_rule_set('main','display','none','important');
css_rule_set('#side','width','100%','important');
css_rule_set('#side','display','block','important');
}
else
{
css_rule_set('main','width',(100 - sidebar)+'%');
css_rule_set('#side','display','block');
}
}
else
{
css_rule_set('#menu a[href*="sidebar"]::after','content','"\u2190"','important');
if (is_mobile())
{
css_rule_set('main','display','block','important');
css_rule_set('main','width','100%','important');
css_rule_set('#side','display','none','important');
}
else
{
css_rule_set('main','width','100%','important');
css_rule_set('#side','display','none');
}
}
There is a way in JavaScript to access value of pseudo elements without any library. To get the value, you need to use the 'getComputedStyle' function. The second parameter is optional.
let elem = window.getComputedStyle(parent, ':before');
alert(elem.getPropertyValue('background'))
This will do alert the value of pseudo element.
let elem = window.getComputedStyle(document.querySelector('#item'), ':after');
console.log(elem.getPropertyValue('content'))
I'm using the object tag to load an html snippet within an html page.
My code looks something along these lines:
<html><object data="/html_template"></object></html>
As expected after the page is loaded some elements are added between the object tags.
I want to get those elements but I can't seem to access them.
I've tried the following
$("object").html() $("object").children() $("object")[0].innerHTML
None of these seem to work. Is there another way to get those elements?
EDIT:
A more detailed example:
consider this
<html><object data="http://www.YouTube.com/v/GGT8ZCTBoBA?fs=1&hl=en_US"></object></html>
If I try to get the html within the object I get an empty string.
http://jsfiddle.net/wwrbJ/1/
As long as you place it on the same domain you can do the following:
HTML
<html>
<object id="t" data="/html_template" type="text/html">
</object>
</html>
JavaScript
var t=document.querySelector("#t");
var htmlDocument= t.contentDocument;
Since the question is slightly unclear about whether it is also about elements, not just about the whole innerHTML: you can show element values that you know or guess with:
console.log(htmlDocument.data);
The innerHTML will provide access to the html which is in between the <object> and </object>. What is asked is how to get the html that was loaded by the object and inside the window/frame that it is producing (it has nothing to do with the code between the open and close tags).
I'm also looking for an answer to this and I'm afraid there is none. If I find one, I'll come back and post it here, but I'm looking (and not alone) for a lot of time now.
No , it's not possible to get access to a cross-origin frame !
Try this:
// wait until object loads
$('object').load(function() {
// find the element needed
page = $('object').contents().find('div');
// alert to check
alert(page.html());
});
I know this is an old question, but here goes ...
I used this on a personal website and eventually implemented it in some work projects, but this is how I hook into an svg's dom. Note that you need to run this after the object tag has loaded (so you can trigger it with an onload function). It may require adaptation for non-svg elements.
function hooksvg(elementID) { //Hook in the contentDocument of the svg so we can fire its internal scripts
var svgdoc, svgwin, returnvalue = false;
var object = (typeof elementID === 'string' ? document.getElementById(elementID) : elementID);
if (object && object.contentDocument) {
svgdoc = object.contentDocument;
}
else {
if (typeof object.getSVGDocument == _f) {
try {
svgdoc = object.getSVGDocument();
} catch (exception) {
//console.log('Neither the HTMLObjectElement nor the GetSVGDocument interface are implemented');
}
}
}
if (svgdoc && svgdoc.defaultView) {
svgwin = svgdoc.defaultView;
}
else if (object.window) {
svgwin = object.window;
}
else {
if (typeof object.getWindow == _f) {
try {
svgwin = object.getWindow();//TODO look at fixing this
}
catch (exception) {
// console.log('The DocumentView interface is not supported\r\n Non-W3C methods of obtaining "window" also failed');
}
}
}
//console.log('svgdoc is ' + svgdoc + ' and svgwin is ' + svgwin);
if (typeof svgwin === _u || typeof svgwin === null) {
returnvalue = null;
} else {
returnvalue = svgwin;
}
return returnvalue;
};
If you wanted to grab the symbol elements from the dom for the svg, your onload function could look like this:
function loadedsvg(){
var svg = hooksvg('mysvgid');
var symbols = svg.document.getElementsByTagName('symbol');
}
You could use the following code to read object data once its loaded completely and is of the same domain:
HTML-
<html>
<div class="main">
<object data="/html_template">
</object>
</div>
</html>
Jquery-
$('.main object').load(function() {
var obj = $('.main object')[0].contentDocument.children;
console.log(obj);
});
Hope this helps!
Here goes a sample piece of code which works. Not sure what the problem is with your code.
<html>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var k = $("object")[0].innerHTML;
alert(k);
$("object")[0].innerHTML = "testing";
});
</script>
<object data="/html_template">hi</object>
</html>
UPDATED
I used this line of Javascript to change the value of a input filed inside an iFrame, taken from How to pick element inside iframe using document.getElementById:
document.getElementById('iframeID').contentWindow.document.getElementById('inputID').value = 'Your Value';
In your case, since you do not have a frame, and since you want to get and not set the value, log it for example with:
console.log(document.getElementById('object').value);
And if you guess or choose an element:
console.log(document.getElementById('object').data);
I am having problems with a javascript function. I want to replace an icon by changing the class.
On my page, I have the following element:
<i class="wait icon" alt="{webui_botstatenotavailable}" title="{webui_botstatenotavailable}" id="{botname}"></i>
The following javascript should change the class, but it does not work:
function incomingBotStatusList(http_request, statusOff, statusOn)
{
if (http_request.readyState == 4)
{
if (http_request.status == 200)
{
if (http_request.responseText.length < 7)
{
// Error
}
else
{
var botStatusList = JSON.parse(http_request.responseText);
for (var key in botStatusList)
{
if (botStatusList.hasOwnProperty(key))
{
var botStatusImage = document.getElementById(key);
if (botStatusImage != null)
{
if (botStatusList[key] == 0)
{
botStatusImage.class.innerHTML = "images/bullet_red.png";
botStatusImage.title = statusOff;
botStatusImage.alt = statusOff;
}
else if (botStatusList[key] == 1)
{
botStatusImage.class.innerHTML = "<i class=\"checkmark green icon\">";
botStatusImage.alt = statusOn;
botStatusImage.title = statusOn;
}
}
}
}
}
}
}
}
Did someone from you know how it will work?
Thanks for your help!
Best Regards
Pierre
I see a couple of problems with your code. First, the <i> element is used to apply italic formatting to text. It is not the HTML code for an icon or an image.
Secondly, you write botStatusImage.class.innerHTML, but the Element.class does not exist, and Element.className is a string. It does not have an innerHTML attribute. So, you could write botStatusImage.className = "new_class_name"; and this would be more correct.
You should then change the image source by calling botStatusImage.setAttribute('src', new_url), where you have set new_url to the new image location.
Check out the javascript reference for the Element class that is returned from document.getElementById: check this link
My recommendation, start simple, then make it complex.
First, try to get the icon to change without the AJAX request. Try writing a function like this:
function changeIcon( imageId, newUrl ){
var element = document.getElementById( imageId );
element.setAttribute( "src", newUrl );
}
Then test this function in the console by passing calling it with the URL's manually.
Once that works, don't change it! Next add the AJAX call, and when you have the Icon url from your server response, all you do is call the function that you already wrote and tested. That way you separate the AJAX code from the image update code and you can test them separately.
The key is smaller functions. Build the easy stuff first, and then call those easy functions from the harder functions. Once you know the easy function works well, it becomes much easier to find problems in the harder functions.
I have a simple JS script to swap out elements containing Flash and replace them with other formats for users who don't have Flash installed.
var hideclass="hidden"
var showclass="empty"
function flashFixMain(){
if (swfobject.hasFlashPlayerVersion("7.0.0")) {
document.getElementById('logoflash').className=showclass;
document.getElementById('logononflash').className=hideclass;
} else {
document.getElementById('logoflash').className=hideclass;
document.getElementById('logononflash').className=showclass;
}
}
And put simply, it doesn't work.
The if statement works fine - putting an alert in the appropriate place pops up fine.
I've checked the source of the appropriate page(s) online, and the element name pops up exactly as written (and only once!).
The class names work fine, as they are used as defaults on the page at the start.
So does anyone have any ideas what I might have missed?
change
document.getElementById('logoflash').class=showclass;
to
document.getElementById('logoflash').className = showclass;
it's className, not class
Instead of using .class you need to use the .className property; for instance:
document.getElementById('logoflash').className = showclass;
In modern browsers you can also use .classList to add a class rather than replace all existing classes:
document.getElementById('logoflash').classList.add(showclass);
As an aside, you could consider moving a few statements around like this:
var hasFlash = swfobject.hasFlashPlayerVersion("7.0.0"),
logoFlash = document.getElementById('logoflash'),
logoNonFlash = document.getElementById('logononflash');
logoFlash.className = hasFlash ? showclass : hideclass;
logoNonFlash.className = hasFlash ? hideclass : showclass;
I wrote up a quick test scenario and without seeing more of your environment, do not see anything that should keep this from working as expected.
The one thing I did notice while doing a write up w/o using jQuery (which I guess you are NOT using?) is that your 'addClass' is really a 'REPLACE' class value. You are simply setting it to a single class.
This makes me think, not having seen your environment, that some OTHER classes might be already assigned to your elements that are getting wiped out. This could be causing unexpected behaviour if some of your display is dependent on these other classes...
Without seeing more of your scenario, that is the only thing that seems like it might be an issue.
Anyway, here is my test setup. You might find something in this useful.
<div id="logoflash" class='something'>
Logoflash
</div>
<div id="logononflash" class='else' >
logononflash
</div>
<script>
var swfobject = {FlashPlayerVersion: '7.0.1', hasFlashPlayerVersion: function(v) {if(v == this.FlashPlayerVersion) return true; else return false;}, myName: 'fakeSWObject' };
console.log(swfobject)
var hideclass = "hidden"
var showclass = "empty"
var getById = function(sID) { return document.getElementById(sID); };
var addClass = function(sID, sClass) { getById(sID).className += ' ' + sClass };
function toggleEl(sID, bState){
console.log('begin toggleEl')
console.log('bState: ' + bState)
try {
if(bState == undefined) {
console.log('Toggling by element state');
getById(sID).style.display = getById(sID).style.display == 'none' ? 'block' : 'none';
} else {
console.log('Toggling by argument');
getById(sID).style.display = !!bState ? 'block' : 'none';
}
} catch (err) {
console.log(err);
}
}
function flashFixMain(){
if (swfobject.hasFlashPlayerVersion("7.0.0")) {
console.log('Is Flash 7.0.0');
toggleEl('logoflash', true);
toggleEl('logononflash', false);
addClass('logoflash', hideclass);
addClass('logononflash', showclass);
} else {
console.log('Is NOT Flash 7.0.0');
toggleEl('logoflash', true)
toggleEl('logononflash', false)
addClass('logoflash', showclass);
addClass('logononflash', hideclass);
}
}
$(function(){ // Yes, this is jQuery to fire after doc is ready
flashFixMain();
})
</script>
use Jquery:
$("#logoflash").addClass(hideclass);
or
$('#logoflash').toggleClass(hideclass, swfobject.hasFlashPlayerVersion("7.0.0"));