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 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 some javascript which looks at the body and finds words and if one is present, it outputs a div. This is useful for many things, however...
What I need to do is also look at the body and all the ALT tags for the page as well.
I found this: Use javascript to hide element based on ALT TAG only?
Which seems to change the ALT attribute, however I want to perform an action.
Here's my JS so far.
var bodytext = $('body').text();
if(bodytext.toLowerCase().indexOf('one' || 'two')==-1)
return;
var elem = $("<div>Text Here</div>");
Thank you.
P.S. I am a N00B/ relatively new at JS, I am doing this for a small project, so I am not sure where to start for this in terms of JS functions.
Updated Answer
Try this out, I commented the code to explain it a bit.
// build array of triggers
var triggers = ['trigger1','trigger2','trigger3'];
// wait for page to load
$(function() {
// show loading overlay
$('body').append('<div id="mypluginname-overlay" style="height:100%;width:100%;background-color:#FFF;"></div>');
// check page title
var $title = $('head title');
for(trigger of triggers) {
if($($title).innerHTML.toLowerCase().indexOf(trigger) >= 0) {
$($title).innerHTML = '*censored*';
}
}
// check all meta
$('meta').each(function() {
var $meta = $(this);
for(trigger of triggers) {
if($($meta).attr('name').toLowerCase().indexOf(trigger) >= 0) {
censorPage();
return; //stop script if entire page must be censored
} else if($($meta).attr('content').toLowerCase().indexOf(trigger) >= 0) {
censorPage();
return; //stop script if entire page must be censored
}
}
});
// check all img
$('img').each(function() {
var $img = $(this);
for(trigger of triggers) {
if($($img).attr('alt').toLowerCase().indexOf(trigger) >= 0) {
censor($img);
}
}
});
// check all video
$('video').each(function() {
var $video = $(this);
for(trigger of triggers) {
if($($video).attr('alt').toLowerCase().indexOf(trigger) >= 0) {
censor($video);
}
}
});
// if you want to be extra careful and check things like background image name,
// you'll have to run this code here - very inefficent
// but necessary if you want to check every single element's background image name:
for($element of $('body').children()) {
for(trigger of triggers) {
if($($element).css('background-image').toLowerCase().indexOf(trigger) >= 0) {
$($element).css('background-image','');
}
}
}
, function() { // Not sure if this is totally correct syntax, but use a callback function to determine when
// when the rest of the script has finished running
// hide overlay
$('#mypluginname-overlay').fadeOut(500);
}});
function censor($element) {
// just a basic example, you'll probably want to make this more complex to overlay it properly
$element.innerHTML = 'new content';
}
function censorPage() {
// just a basic example, you'll probably want to make this more complex to overlay it properly
$('body').innerHTML = 'new content';
}
---Original Answer---
I'm not sure exactly what you would like to do here, you should add more detail. However if you choose to use jQuery, it provides tons of useful methods including the method .attr(), which lets you get the value of any attribute of any element.
Example:
var alt = $('#my-selector').attr('alt');
if (alt == 'whatYouWant') {
alert('yay');
} else {
alert('nay');
}
You're using jQuery lib, you could select elements by attribute like:
$('[alt="one"]').each(function(el){
// do something
var x = $(el).arrt('alt');
});
If you use selector $('[alt]') you can get elements that have this attribute set, and then check the value of the element if you have a more complicated selection.
Than you have to change your return, as you could not put a div inside an ALT tag, it didn't work.
Here is about what is your expected output.
UPDATE
As you want to change all images and video in a page, the way to do this with jquery is through $.replaceWith():
$('img,video').replaceWith($('<div>Text Here</div>'));
If you need to filter the elements:
$('img,video').each(function(el){
if($(el).prop('tagName') == 'IMG' &&
$(el).attr('alt') == 'the text...') {
$(el).replaceWith($('<div>Text Here</div>'));
}
})
But I'm not an expert on Chrome Extensions, I just put this code here in jQuery, as you was using jQuery.
Of course it could be done, with much code with plain javascript and the DOM API.
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"));