I have an <img> in an HTML document that I would like to highlight as though the user had highlighted it using the mouse. Is there a way to do that using JavaScript?
I only need it to work in Mozilla, but any and all information is welcome.
EDIT: The reason I want to select the image is actually not so that it appears highlighted, but so that I can then copy the selected image to the clipboard using XPCOM. So the img actually has to be selected for this to work.
Here's an example which selects the first image on the page (which will be the Stack Overflow logo if you test it out on this page in Firebug):
var s = window.getSelection()
var r = document.createRange();
r.selectNode(document.images[0]);
s.addRange(r)
Relevant documentation:
http://developer.mozilla.org/en/DOM/window.getSelection
http://developer.mozilla.org/en/DOM/range.selectNode
http://developer.mozilla.org/en/DOM/Selection/addRange
You might also want to call s.removeAllRanges() before s.addRange(r).
What, exactly, are you trying to do? If you're using XPCOM, you're presumably writing an application or an extension for one; can't you just get the image data and put it on the clipboard directly?
My personal choice for selecting elements is jquery:
Then to get the element of your choice is:
$("img#YOURIMAGEHERE").focus();
You can swap the source of the image, as in img.src = "otherimage.png";
I actually did this at one point, and there are things you can do to pre-load the images.
I even set up special attributes on the image elements such as swap-image="otherimage.png", then searched for any elements that had it, and set up handlers to automatically swap the images... you can do some fun stuff.
Sorry I misunderstood the question! but anyways, for those of you interested in doing what I am talking about, here is an example of what I mean (crude implementation, I would suggest using frameworks like jQuery to improve it, but just something to get you going):
<html>
<body>
<script language="javascript">
function swap(name) {
document.getElementById("image").src = name;
}
</script>
<img id="image" src="test1.png"
onmouseover="javascript:swap('test0.png');"
onmouseout="javascript:swap('test1.png');">
</body>
</html>
The basic idea of the "highLight" solution is ok, but you probably want to set a "static" border style (defined in css) for the img with the same dimensions as the one specified in the highLight method, so it doesn't cause a resize.
In addition, I believe that if you change the call to "highLight(this)", and the function def to "highLight(obj)", then you can skip the "document.getElementById()" call (and the specification of the "id" attribute for "img"), as long as you do "obj.style.border" instead.
You probably also need to spell "highLight" correctly.
Give the img tag an ID. Use document.getElementById('id').
<script type="text/javascript" language="javascript">
function highLight()
{
var img = document.getElementById('myImage');
img.style.border = "inset 2px black";
}
</script>
<img src="whatever.gif" id="myImage" onclick="hightLight()" />
EDIT::
You might try .focus to give it focus.
Related
I'm currently working on a userscript, but I have a problem.
I'm trying to replace an image with another one.
I thought I could do it this way:
$(".subforumicon.ajax_mark_read").each(function() {
$(this).html($(this).html().replace(/http:\/\/x\.hackforums\.net\/images\/modern_pl\/minion.gif/g, "http://megaviews.net/hf/designcostumizer/themes/green/minion.png"));
});
However, this will do nothing. When I paste this code in the javascript console, it just displays all img-tags with this picture:
I don't want to replace everything by using $("body").html(), as this can cause problems with the website (somehow).
Before I started working with jQuery, I used document.body.innerHTML, what caused issues on the page, but with document.getElementById() it worked, so I don't think it was my fault. ;)
I'm quite new to jQuery, so could somebody please explain me why my above code doesn't work?
It does not work because the selected elements are img and there is nothing below the img elements.. as .html() selects or sets the INSIDE content (like innerHTML). not outerHTML so you cannot access the attributes of the img element itself by this mean.
You should work on the img's src attribute as already proposed in other posts.
Use .prop()
you need $('img') as you are changing image src only.
so replace img attribute src only.
why traverse through all full html you need to focus on src property only.
$('img').prop('src', function (_, old_src) {
return old_src.replace(/http:\/\/x\.hackforums\.net\/images\/modern_pl\/minion.gif/g, "http://megaviews.net/hf/designcostumizer/themes/green/minion.png");
});
or better if you want to change all images attribute src
$('img').prop('src','http://x.hackforums.net/images/modern_pl/minion.gif');
I have an image that will form the background of an html page, and I want to superimpose speech bubbles over it. I've figured out how to make bubbles with css, and set their placement. But I cannot figure out how I will populate the bubbles (the div elements). Text messages will populate files, and I need to grab the strings and display them in the bubbles, refreshing the bubble content as messages come in. Any thoughts?
Assuming one of your bubbles contains a DIV which looks like this:
<div id="bubble1">This is the text</div>
You can use Javascript to easily change the text content. Using a JS library like jQuery is recommended. Here is a code example which changes the text:
<script>
$(document).ready(function()
{
$('#bubble1').text('This is the changed text'); // to change the text
$('#bubble1').html('This has <b>some</b> formatting'); // to change the html
});
</script>
Don't forget to include jQuery itself with a line like:
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
I couldn't understand where you are getting your strings from, if you let me know, I could update the answer.
If you are unfamiliar with jQuery, take a look here.
I think this will answer your question:
http://nicolasgallagher.com/pure-css-speech-bubbles/
Keep in mind that this is css3, so older browsers can have problems with that.
I have a couple of divs with background images. I would like to know how I can preload those background-images with a gif image since some of the background images are quite large. Doing the following does not work:
HTML:
<div id="glykopeels" onload="loadImage()">Glykopeels Content</div>
<div id="facials" onload="loadImage2()">Facials Content</div>
CSS:
#glykopeels{
background: #ebebeb url(http://lamininbeauty.co.za/images/products/preloader.gif) no-repeat top right;
background-size: contain;
}
#facials{
background: #ebebeb url(http://lamininbeauty.co.za/images/products/preloader.gif) no-repeat top right;
background-size: contain;
}
JS:
function loadImage(){
document.getElementById('glykopeels').style.background = '#ebebeb url(http://lamininbeauty.co.za/images/products/glykopeel.jpg);';
}
function loadImage2(){
document.getElementById('facials').style.background = '#ebebeb url(http://lamininbeauty.co.za/images/products/facial.jpg);';
}
I guess defining a different ID for that element in the onload function and defining css for that new ID is another possibility? Thus changing only the id of that element inside the onload function?
Thank you
First: there is no onload attribute for div's. EDIT: please read comments below, very interesting!
Secondly, you should place the url between quotes (escaping them if needed): url('http://lamininbeauty.co.za/images/products/facial.jpg')
Third, there was no image called preloader.gif, yet there was a image called loader.gif, so I used that one to 'fix' your css part for my solution in the jsfiddle demo link at the bottom.
During SO's server-move, I wrote a simple custom function for you that does exactly what you want.
Tested in IE6 and FF12.
To test this: please clear your browsers buffer, otherwise you can't SEE it in action (it would go too fast), since the images will probably be buffered on second view (again, perfect for your goal)!
JavaScript:
var repBg=function(a, t){ t=t||'*'; // by GitaarLAB
var c=document.getElementsByTagName(t), i=c.length, r=[];
while(i--){if (c[i].getAttribute(a)){r.push(c[i]);}} c=r; i=c.length;
repBg.exec=function(){
c[this['data-i']].style.background="#ebebeb url('"+this.src+"') no-repeat top right";
};
while(i--){ if (c[i].getAttribute(a)) {
r=new Image();
r.onload=repBg.exec;
r['data-i']=i;
r.src=c[i].getAttribute(a);
}}
};
// one could run repBg onload, but better to run it when the image has actually loaded, see html!
// window.onload=function(){ repBg('data-bg_img','div'); };
In your BODY: Add the attribute 'data-bg_img' (as per html5 convention, start with data-) to the elements you want to use this technique on and have it contain your background url, like this:
<div id="glykopeels" data-bg_img="http://lamininbeauty.co.za/images/products/glykopeel.jpg">Glykopeels Content</div>
The 'optional' initialization in your BODY:
<!--
trigger the replace background function when the loader image has actually loaded!
rewriting the onload with nothing to prevent infinite loop in IE6 (and greater?) !!
-->
<img src="http://lamininbeauty.co.za/images/products/loader.gif" style="display:none;" onload="this.onload=null; repBg('data-bg_img','div');">
Manual/explanation:
Images DO have a onload-event, so we place a loading-image in the html (at the bottom), that will trigger it's own onload-event, calling repBg() as soon as the browser has actually downloaded this loading-image!!!
The function repBg() takes up to 2 arguments:
the first mandatory string that contains the attribute that should be selected,
the second optional argument can define tagname (to limit the first argument).
When invoked, function repBg() will then search the body for elementTagNames that adhere to the second argument or * and then filter them with the first argument.
For each htmlObject that remains in the filtered htmlObjectCollection, a new image is created (not appended to the body) with the htmlObject's attribute-value (url) corresponding to the function's first argument as image-source, together with the htmlObjectCollection's referring id (attribute data-id) for reference.
As soon as these images load, they fire their onload event: calling repBg's exec method that replaces the background of the referenced htmlObject with the new freshly loaded (big) background-image (and the rest of your css). For further modularity you could expand on that function.
Lastly, note: the background images load in order they appear in source, aka the way you expect things to work!!
You can see it in action in this fiddle: http://jsfiddle.net/epdDa/
UPDATE VERSION 2: GRACEFUL FALLBACK!! AND COPY-PASTE NOBRAIN SOLUTION
It annoyed the living daylights out of me that my first solution did not provide graceful fallback. So I made a different solution that provides graceful fallback.
Also fully tested in IE6 and FF12
It works like this:
In your BODY: SIMPLY set your div's class to 'preload' and set it's style-attribute to the backgroundimage it should normally load. Like this:
<div id="facials" class="preload" style="background: #ebebeb url('http://lamininbeauty.co.za/images/products/facial.jpg') no-repeat top right;">Facials Content</div>
That was easy right?
Then place the following script in the HEAD (this is important) of the HTML:
// getElementsByClass original by dustin diaz, modified by GitaarLAB
document.getElementsByClassName=document.getElementsByClassName||function(searchClass,node,tag) {
var classElements = [], i=0, j=0;
if (!node){node = document;}
if (!tag){tag = '*';}
var els = node.getElementsByTagName(tag);
var elsLen = els.length;
var pattern = new RegExp('(^|\\\\s)'+searchClass+'(\\\\s|$)');
for (; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i]; j++;}
} return classElements;
};
var repBg=(function(n,u,p,a,i,r){ // by GitaarLAB
window.onload=function(){repBg(1);};
i=new Image(); i.onload=function(){this.onload=null; repBg(2);};
document.write("<style>."+n+"{background:"+p+" url("+u+") "+a+
" !important; background-size: contain !important;}"+
"</style>");
i.src=u; r=0;
return function(t){
r=r+t; if(r>2){
var c=document.getElementsByClassName(n), i=0, l=c.length, s;
repBg.exec=function(){
document.getElementById(this['data-id']).className='';
};
for(;i<l;i++){
r=new Image();
r.onload=repBg.exec;
r['data-id']=c[i].getAttribute('id');
s=c[i].getAttribute('style');
try { // sane browsers
r.src=s.match(/url\('?([^'"]*)'?\)/i)[1];
} catch(e) { // <IE8
r.src=s.cssText.match(/url\('?([^'"]*)'?\)/i)[1];
}
}
}
};
})('preload','http://lamininbeauty.co.za/images/products/loader.gif','#ebebeb','no-repeat top right');
Explanation:
It took me all night.. but I found a way.
If javascript is enabled, function repBg will start by writing an extra style-block to the documents head (where it is located, note to place it after your last css script), that sets the loader-background-image for all elements with the class 'preload' (thus displaying the load-image at pageload).
If a load-test image for the loading-image is loaded AND the window is loaded (to get to all the elements in the body), then it does basically the same as version 1. Only this time we fetch and match the url from the element's style-atribute and onload subsequently empty the element's style-attribute.
Since this function auto-executes and overwrites itself with a version similar to version 1 (as above), you can simply adjust parameters at the last line of function 'repBg'.
Note that: in it's initial sate repBg accepts a maximum of 4 arguments: className, Url, cssPrepend and cssAppend.
To see it in action (don't forget to clean your browsers buffer as explained),
click this fiddle: http://jsfiddle.net/epdDa/1/
Whoever uses this function, I would greatly appreciate it if you credit me!
UPDATE:
Extra explanations and answers to comments.
Main differences between the 2 versions
Technically both versions use almost the same techniques so there is no real difference there.
With version 1 the javascript is the glue that IS NEEDED to make the page work, but works in valid true xhtml and plain html.
However, people with javascript turned off will get a nonfunctional site (with only loading-gifs displayed). Note that all other current answers, including the direction you where going, suffer from this problem!
With version 2 the javascript is only the spice that enhances the page-interaction (the way websites should be coded), but only works in html (or invalid xhtml).
However this should make sure that people with javascript turned off still see a normal functioning page. IE: javascript is NOT NEEDED to display the site correctly. This concept is called 'graceful fallback' or 'degrading gracefully'. My vote no 1 for version 2.
Extra bonus: this path gives you plain vanilla validating and SEMANTIC html since you use ancient trusty in-line style, id and class. My vote no 2 for version 2
Why did I choose to use in-line css? Why 'must' you use in-line css for this to work?
First of all, I spent hours to avoid in-line css. (I did not loose them, I learned way's that did not work, just as useful). Next, I want to point out that again all current answers including the direction you were going, had the actual background image url separated from the css, while in the css you were setting the loader image on each div separately, something where a class would have made more sense. Version 2 simply uses a configurable classname.
Both reading and writing css blocks in the document's HEAD is kind of a mess..
And did I mention linked external css files..??
In my opinion, all this would need so much extra code and cpu-cycles AND blocking/halting the browser on every pageload, in order for the core-priciple to work: the last valid css-rule applies. So the loading image is displayed as soon as possible since it is the specified background image at pageload, exactly what one would want from such a feature. And if the element is no longer part of the 'preload' class? Right: it's inline css takes effect, updated as fast as the browsr can render (if the image is already loaded). Nice.
So if you sacrifice (true) xhtml-support by simply using document.write, it currently still turns out this way is the 'best' way to go (as you can read in the previous 2 links). AND it would still work with an external linked css. My third (KISS-)vote for version 2.
My fourth vote for version 2 is because: the repBg function is prepared to have it's exec method(=function) 'upgraded' so you can only take out the 'preload' value from the class' valuelist. A simple replace() would suffice (currently left out for speed).
My fifth and final vote for version 2 is that because of it's graceful fallback setup, it is also relatively easy to fix for or block some browsers to use the extra 'spice'.
Finally, as for speed: I think version 2 will always feel snappier: onload-image is displayed almost as fast as the browser can fetch it (as if this extra css was always there to begin with), the loading-animations load snappy since: their load is already initiated in the head, and the browser will not download the overruled images until called for by the function. Plus they look interactive without distraction. But.. when the actual background images are loaded and the css updates: bam! the image is there, without the top-to-bottom-scanning'-effect'. That effect feels damn snappy to. Actually I'm convinced and will be doing an adaptation for images in the galary, for the snap-feel and increased perceived initial pageload.. Note, this is my opinion. Your mileage may vary haha.
Good luck!!
(and please vote if you like/use this idea/function, thank you!!)
1) div elements doens't have a load event, this event is only for body, images and script tags.
EDIT: Like pointed by #icktoofay, in the HTML spec the onload exists for all elements, however this is not supported by the major browsers (yet).
2) place this script tag at the end of your html page:
<script>
function loadImages() {
var glykopeels = document.getElementById('glykopeels');
var facials = document.getElementById('facials');
glykopeels.style.backgroundImage = 'url(http://lamininbeauty.co.za/images/products/glykopeel.jpg)';
facials.style.backgroundImage = 'url(http://lamininbeauty.co.za/images/products/facial.jpg)';
3) You can set style.background like you did, but do not put the ; at the end of the string, otherwise it will not work.
fiddle: http://jsfiddle.net/pjyH9/
EDIT
Seems like the loader image does not show because once the browser receive the first bytes of the new image it removes the loader.gif from the background. Let's take another approach.
Here is a function that will load the image to cache and then - when image is loaded - set the image to the background of the element with the specified id.
function loadImageToBackground(elementId, imageUri) {
var img = new Image();
img.onload = function() {
document.getElementById(elementId).style.backgroundImage = "url('" + imageUri + "')";
};
img.src = imageUri;
}
The on the elements that you want the loader:
// past the element id and the image url to the function
loadImageToBackground('glykopeels', 'http://image....');
I'm pretty sure that this will work. The function loadImageToBackground do the basic work, you can extend and add more functionalies if you want.
Here is fiddle with a working example: http://jsfiddle.net/pjyH9/19/
(It loads 2 images with 1.5mb each, so you can see the loader in action).
I think what you're trying to do is get the background image to switch out to the big JPG image after it's loaded. You should be able to adapt something like this to work for you:
<html>
<head>
<title>Image Load Test</title>
<script type="text/javascript">
function loadImage(preloader, imageDiv) {
document.getElementById(imageDiv).style.background = '#ebebeb url('+preloader.src+') no-repeat top right';
// I think resetting the background property also resets backgroundSize.
// If you still want it 'contained' then you need to set the property again.
document.getElementById(imageDiv).style.backgroundSize = 'contain';
}
</script>
<style type="text/css">
#testImage {
background: #ebebeb url(small-image.gif) no-repeat top right;
background-size: contain;
}
#preloads { display: none; }
</style>
</head>
<body>
<div id="testImage">Some Content</div>
<div id="preloads">
<img src="full-image.jpg" onload="loadImage(this, 'testImage')">
</div>
</body>
</html>
The main difference here is that I'm preloading the JPG image in an <img> that's hidden in a <div> with the display: none property to keep it hidden. I'm not sure exactly what the onLoad event does for divs, but I'm pretty sure it's not what you're wanting. Putting an onLoad event in an img element causes the event to fire once the image has fully loaded, which I believe is what you want.
EDIT: I added a line in the JavaScript to reset the background-size property. If that's not what you wanted then just ignore that part.
I have a parent div gal1, inside which there can be further divs and content, but only one img element without an id as you can see below. Now I want to use only Javascript (no jQuery) to change the style of this image, using gal1 as argument (because the rest of the structure inside this div may vary, only this one image will always be there somewhere). I couldn't find any other stackoverflow question that addresses exactly my situation.
<div class="gallery-preview" id="gal1">
<div class="gallery-preview-img" id="gal-img1">
<img src="galleries/kevin-carls/Monks.jpg">
</div>
<div class="gallery-preview-text" id="gal-text1">
<span class="gallery-name" href="">Road to India</span><br/>
<span class="artist-name" href="">Kevin Carls</span>
</div>
</div>
Than you can make use of method called getElementsByTagName('img') than you should get image and update it.
document.getElementById(gal1).getElementsByTagName('img');
get the content by using id, and then query images by using getElementsByTagName
function getImages(contentId) {
var content = document.getElementById(contentId);
// only one image, just return an item; or you can return an array
if (content) return document.getElementsByTagName('img')[0];
}
You can insert CSS which may be more efficient if you have to do this in more than this single case.
http://jsfiddle.net/65Ggv/
var style_rules = [];
style_rules.push("#gal1 img { border: 3px solid green; } ");
var style = style_rules.join("\n");
var el=document.createElement("style");
el.appendChild(document.createTextNode(style));
el.type="text/css";
document.head.appendChild(el);
Unless you absolutely need to pick the colors or border sizes dynamically, which I doubt because you are an admitted beginner, stuffing stylesheets in with Javascript is a Rube Goldberg device. It seems nifty to be able to do this, but if your application is important to you, you will regret it. (You might as well use innerHTML to stuff in a stylesheet in that case -- at least it will be faster than making DOM calls.)
Pranay Rana's answer to use getElementsByTagName is the best option if your constraints are actually stable (only one img). Obtain an element reference el, to gal1, using getElementById, then var myimg = el.getElementsByTagName("img") and you are almost done.
If you insist upon funking with the style nodes, you can stuff whatever properties you want into the style property of myimg. It becomes inline style.
Even so, you almost certainly do not need to stuff in novel rules, and changing inline style is often avoidable. It is more predictable and stable to modify the class attribute on myimg, and use a predefined set of style classes for the cases you need to handle. This will give a nice clean separation of the style from the script, and avoid both the in-lining of the style rules and run-time mutilation of the style tree by code injection.
We've got a little tool that I built where you can edit a jQuery template in one field and JSON data in another and then hit a button to see the results immediately within the browser.
I really need to expand this though so the designer can edit a full CSS stylesheet within another field and when we render the template, it will have the CSS applied to it. The idea being that once we've got good results we can take the contents of these three fields, put them in files and use them in our project.
I found the jQuery.cssRule plugin but it looks like it's basically abandoned (all the links go nowhere and there's been no development in three years). Is there something better or is it the only game in town?
Note: We're looking for something where someone types traditional CSS stylesheet data in here and that is used immediately for rendering within the page and that can be edited and changed at will with the old rules going away and new ones used in their stead. I'm not looking for something where the designer has to learn jQuery syntax and enter in individual .css("attribute", "value") type calls to jQuery.
Sure, just append a style tag to the head:
$("head").append("<style>p { color: blue; }</style>");
See it in action here.
You can replace the text in a dynamically added style tag using something like this:
$("head").append("<style id='dynamicStylesheet'></style>");
$("#dynamicStylesheet").text(newStyleTextGoesHere);
See this in action here.
The cleanest way to achieve this is by sandboxing your user-generated content into an <iframe>. This way, changes to the CSS won't affect the editor. (For example, input { display:none; } can't break your page.)
Just render out your HTML (including the CSS in the document's <head>, and write it into the <iframe>.
Example:
<iframe id="preview" src="about:blank">
var i = $('#preview')[0];
var doc = i.contentWindow || i.contentDocument;
if (doc.document) doc = doc.document;
doc.open('text/html',true);
doc.write('<!DOCTYPE html><html>...</html>');
doc.close();
If the user should be able to edit a whole stylesheet, not only single style attributes, then you can store the entered stylesheet in a temporary file and load it into your html document using
$('head').append('<link rel="stylesheet" href="temp.css" type="text/css" />');
sounds like you want to write an interpreter for the css? if it is entered by hand in text, then using it later would be as simple as copy and pasting it into a css file.
so if you have a textarea on your page to type in css and want to apply those rules when you press the button, you could use something like this (only pseudocode, needs work):
//for each css id in the text area
$.each($('textarea[name=cssTextArea]').html().split('#'), function({
//now get each property
$.each($(this).split(';'), function(){
$(elem).css({property:value});
});
});
then you could write something to go through each element that your designer typed in, and get the current css rules for it (including those that you applied using some code like the snippet above) and create a css string from that which could then be output or saved in a db. It's a pain and much faffing around with substrings but unfortunately I don't know of a faster or more efficient way.
Hope this atleast gives you some ideas