I'm trying to build a browser bookmarklet that lets a user save a quotation (block of text) - and with the press of the bookmarklet - will save the quote, along with a timestamp and URL to their profile inside a web app.
You can see the code I've written below, but running into a few problems.
Wrapping the code nicely to work in a bookmarklet.
Obviously using the $post may be heavy given some pages will require it to be added by the bookmarklet.
Any ideas on how to proceed?
You can see where I'm at currently here http://jsfiddle.net/Rh7zx/1/
(function() {
function getSelectionHtml() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}
function saveToBiblio() {
var url = window.location;
var dateSaved = new Date();
var selectedText = getSelectionHtml();
console.log(url + dateSaved + selectedText);
/*
do the $post here
*/
}
)();
1) Wrapping the code nicely to work in a bookmarklet.
A bookmarklet is just JavaScript code encoded into a URL using the javascript: pseudo-protocol. There are several sites and tools that will take your code and turn it into a bookmarklet. The fundamental thing is to make it so that when the code is run, the thing you want to do occurs. Your code currently defines two functions, but doesn't call either of them. You'd want to call the relevant one. It's also generally best to wrap your bookmarklet code in a scoping function so you don't add to the page's global namespace (because of the possibility of conflicts):
(function() {
// Your code here
)();
Some of the bookmarklet makers may have an option to do that for you, but doing it yourself is trivial.
2) Obviously using the $post may not work cross browser.
That will work fine cross-browser, but won't work in pages that don't have jQuery loaded, and loading jQuery into the page is probably overkill. I'd use XMLHttpRequest directly.
Related
I'm using IE Edge's emulator mode to test some work and one of the project I work on requires IE8. The emulator is pretty useful to debug some stuff that the original IE8 is doing a good job at blackboxing. I'm trying to find a way around this bug since Microsoft isn't willing to fix it.
The problem is that IE8 emulator hangs on SVG image load. I'm currently using this SVG fallback library which works great on the real IE8 but I was wondering if there is a way to modify events or object prototypes using Javascript to change the behavior of the browsers before it tries to load SVG images when parsing HTML? Is there such a way to solve this issue or should I just live with this bug? I have this dirty workaround which does the trick but I'm hoping to find a more proactive solution.
var fixMySVG = setInterval(function () {
var elements = document.getElementsByTagName('img');
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
element.src = element.src.replace(/^(.+)(\.svg)(\?.)*$/ig, '$1.' + 'png' + '$3');
}
if (document.readyState == 'complete') {
clearInterval(fixMySVG);
}
}, 100);
There is no error, the image is just stuck in an 'uninitialized' state (so I cannot use the onerror event). I'm also unaware of any onbeforeoload event I could use.
Is using interval the only solution?
Edit
I realize there is no perfect solution but to solve basic <img> and backgroundImage style, using interval seems to do an good job without performance hit. On top of that fall back images seems to load faster. I updated my SVG fallback to use interval instead of using onload events which solve both IE8 emulator and the real IE8.
It's a really odd bug, since there is no older-version emulation mode in Edge, just mobile one and user-agent string emulation, which will just allow you "to debug errors caused by browser sniffing", but in no way it is related to some feature non-support.
Using your fallback is one out of many options but there is no "clean" way to do this. On top of that it will not solve SVG images using <object>, <iframe> or <embded> elements, nor inline <svg> elements.
So this doesn't point directly to your issue, which should be fixed by IE team since it's a bug in their browser, but just for the hack, here is a way to change the src of an image before the fetching of the original one starts.
Disclaimer
Once again, this is a hack and should not be used in any production nor development site maybe just for an edge debugging case like yours and for experimentation but that's all !
Note : this will work in modern browsers, including Edge with IE8 user-string Emulation set, but not in the original IE8.
Before the dump
This code should be called in the <head> of your document, preferably at the top-most, since everything that is called before it will be called twice.
Read the comments.
<script id="replaceSrcBeforeLoading">
// We need to set an id to the script tag
// This way we can avoid executing it in a loop
(function replaceSrcBeforeLoading(oldSrc, newSrc) {
// first stop the loading of the document
if ('stop' in window) window.stop();
// IE didn't implemented window.stop();
else if ('execCommand' in document) document.execCommand("Stop");
// clear the document
document.removeChild(document.documentElement);
// the function to rewrite our actual page from the xhr response
var parseResp = function(resp) {
// create a new HTML doc
var doc = document.implementation.createHTMLDocument(document.title);
// set its innerHTML to the response
doc.documentElement.innerHTML = resp;
// search for the image you want to modify
// you may need to tweak it to search for multiple images, or even other elements
var img = doc.documentElement.querySelector('img[src*="' + oldSrc + '"]');
// change its src
img.src = newSrc;
// remove this script so it's not executed in a loop
var thisScript = doc.getElementById('replaceSrcBeforeLoading');
thisScript.parentNode.removeChild(thisScript);
// clone the fetched document
var clone = doc.documentElement.cloneNode(true);
// append it to the original one
document.appendChild(clone);
// search for all script elements
// we need to create new script element in order to get them executed
var scripts = Array.prototype.slice.call(clone.querySelectorAll('script'));
for (var i = 0; i < scripts.length; i++) {
var old = scripts[i];
var script = document.createElement('script');
if (old.src) {
script.src = old.src;
}
if (old.innerHTML) {
script.innerHTML = old.innerHTML;
}
old.parentNode.replaceChild(script, old);
}
}
// the request to fetch our current doc
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && (this.status == 200 || this.status == 0)) {
var resp = this.responseText || this.response;
parseResp(resp);
}
};
xhr.open('GET', location.href);
xhr.send();
})('oldSrc.svg',
'newSrc.svg');
</script>
And a live example which won't work with the IE8 UA string since plnkr.co just doesn't allow this browser on his website :-/
I am making a live editor for my website. I have the CSS and HTML parts down, only issue is the JS part now. Here is a snippet of the code
var frame = $('#preview_content'),
contents = frame.contents(),
body = contents.find('body');
csstag = contents.find('head').append('<style></style>').children('style');
java = contents.find('head').append('<script><\/script>').children('script');//Issues here
$('.area_content_box').focus(function() {
var $this = $(this);
var check = $this.attr('id');
$this.keyup(function() {
if (check === "html_process"){
body.html($this.val());
} else if(check === "css_process") {
csstag.text($this.val());
} else if (check === "java_process"){
java.text( $this.val() );
}
});
});
Problem is it is not injecting script tags in the iframes body nor the head when ever I try this. I've read up on injecting and some issues containing the ending script tag. I need to figure out how to inject script tags, really want them in the head but if it is easier in the body that is fine.
jfriend00 - I will be focusing on making this vanilla, if you think I should honestly.
So any words of advice on how to go about making my editor work correctly with the injecting JS?
These two lines of code look like they could have problems:
csstag = contents.find('head').append('<style></style>').children('style');
java = contents.find('head').append('<script><\/script>').children('script');//Issues here
It seems like it would be much better to create the style tag and remember that DOM element.
var iframe = document.getElementById("preview_content");
var iframewindow = iframe.contentWindow || iframe.contentDocument.defaultView;
var doc = iframewindow.document;
var csstag = doc.createElement("style");
var scripttag = doc.createElement("script");
var head = doc.getElementsByTagName("head")[0];
head.appendChild.cssTag;
head.appendChild.scriptTag;
$('.area_content_box').focus(function() {
var $this = $(this);
var check = this.id;
$this.keyup(function() {
if (check === "html_process") {\
// I would expect this to work
doc.body.html($this.val());
} else if(check === "css_process") {
// I don't know if you can just replace CSS text like this
// or if you have to physically remove the previous style tag
// and then insert a new one
csstag.text($this.val());
} else if (check === "java_process"){
// this is unlikely to work
// you probably have to create and insert a new script tag each time
java.text( $this.val() );
}
});
});
This should work for the body HTML and it may work for the CSS text into the style tag.
I do not believe it will work for the javascript as you can't change a script by assigning text to the tag the way you are. Once a script has been parsed, it's in the javascript namespace.
There is no public API I'm aware of for removing previously defined and interpreted scripts. You can redefine global symbols with subsequent scripts, but not remove previous scripts or their effects.
If this were my code, I'd remove the previous style tag, create a new one, set the text on it before it was inserted in the DOM and then insert it in the DOM.
If you're not going to do it that way, then you'll have to test to see if this concept of setting .text() on an already inserted (and parsed) style tag works or not in all relevant browsers.
For the script tag, I'm pretty sure you'll have to create a new script tag and reinsert it, but there's no way to get rid of older code that has already been parsed other than redefining global symbols. If you really wanted to start fresh on the code, you'd have to create a new iframe object from scratch.
There are other issues with this too. You're installing a .keyup() event handler every time the .area_content_box gets focus which could easily end up with many of the event handlers installed, all getting called and all trying to do the same work.
I'm trying to write a little bookmarklet that can extract some text from the active page and load that into the clipboard.
The extraction is easy enough, but I'm really stuck doing the clipboard-copying part. Currently, I'm just alerting the text and hitting Ctrl+C to copy the text from the message-box, which isn't ideal.
I've read How to Copy to Clipboard in JavaScript and other questions that suggest I use zeroclipboard, but I have no idea how one would make that work from a bookmarklet, considering I have to load external flash and javascript resources to be able to use the library.
I have no issues with messing up the page's DOM to accomplish this or having to enable some permissions on my browser (Google Chrome), considering this is just a private bookmarklet.
Any pointers would be appreciated.
There is a nice little bookmarket in Github Gist that does the core of what you want -- copying to the clipboard. It does not use any external libraries, which I think of as an advantage.
As written, it copies some static text, but toward the bottom it talks about adapting it to other uses, such as copying the page title.
Since you've stated that 'The extraction is easy enough ...', you should be easily be able to adapt that gist to what you want to do.
I tried the plain vanilla version of the bookmarklet, because I have some static text that I often need to transfer to my clipboard. It works very well in Chrome 61 with no modifications. But make sure you read the comments; some people have suggestions on getting it to work in other browsers and scenarios.
Here is the code that I tested, already minified and ready to turn into a bookmarklet:
javascript:!function(a){var b=document.createElement("textarea"),c=document.getSelection();b.textContent=a,document.body.appendChild(b),c.removeAllRanges(),b.select(),document.execCommand("copy"),c.removeAllRanges(),document.body.removeChild(b)}("Text To Copy");
Gist has the pre-minified code as well.
Since the new Clipboard API, this is easy in browsers that support it:
javascript: navigator.clipboard.writeText('some text from somewhere');null;
Caveat: Any alerts or prompts in your bookmarklet will cause the document to lose focus, and the clipboard API will become unavailable. In that case you need to move focus back into the document before any subsequent clipboard operations will work:
const oldFocus = document.activeElement;
/* do popup stuff here */
oldFocus.focus();
/* do clipboard stuff here */
With recent versions of Firefox, interacting with the clipboard via a bookmarklet in general won't work due to missing permissions (see this information for more details). There may be a way, however, to have the bookmarklet display a button, and perform the clipboard interaction in the context of a button-click event handler.
A possibly more straightforward solution is to use a user-script manager, and define your bookmarklet in the form of a user-script that you can activate via a keyboard combination. See, for example this user script, reproduced here for completeness:
// Add the following as a user-script (via an extension like https://github.com/violentmonkey/violentmonkey) in order to copy the
// current webpage and selected text to the clipboard in a format suitable for pasting into an org-mode document.
// To execute the action, you need to press Alt-C on a webpage, though this can be modified by changing the keycode
// used in the onkeyup function.
// ==UserScript==
// #name Copy Org-mode Link
// #namespace Violentmonkey Scripts
// #match *://*/*
// #grant clipboardWrite
// ==/UserScript==
function main() {
function copyTextToClipboard(text) { var textArea = document.createElement("textarea"); textArea.style.position = 'fixed'; textArea.style.top = 0; textArea.style.left = 0; textArea.style.width = '2em'; textArea.style.height = '2em'; textArea.style.padding = 0; textArea.style.border = 'none'; textArea.style.outline = 'none'; textArea.style.boxShadow = 'none'; textArea.style.background = 'transparent'; textArea.value = text; document.body.appendChild(textArea); textArea.select(); try { var successful = document.execCommand('copy'); var msg = successful ? 'successful' : 'unsuccessful'; console.log('Copying text command was ' + msg); } catch (err) { console.log('Oops, unable to copy'); } document.body.removeChild(textArea); }; var url = encodeURIComponent(location.href); url = url.replace(/%253A/g, ':').replace(/%252F/g, '/'); var title = document.title; title = title.replace(/\[/g, '{'); title = title.replace(/\]/g, '}'); var sel_text = window.getSelection(); copyTextToClipboard('[['+url+']['+title+']]'+'\n\n'+sel_text);
}
// listen for Alt-C key-combination, and then execute
document.onkeyup=function(e){
var e = e || window.event; // for IE to cover IEs window object
if(e.altKey && e.which == 67) {
main();
return false;
}
}
An answer that's a bit unusual: open a blank page from which the user will copy the text:
<a href="javascript:window.open('data:text/html, <html contenteditable>sup<script>document.execCommand(\'selectAll\')</script></html>')">
Copy the text “sup”
</a>
Just replace sup by the text you want the user to copy.
JS Bin example
Here's how I solved it, using the technique #zzzzBov mentioned in his answer, to import zeroclipboard into the page via a bookmarklet.
When the bookmarket runs, a hand cursor appears on hovering over anywhere on the body. Clicking will copy (for example) the document's title to the clipboard.
(Links to zeroclipboard resources have been replaced with placeholders, and multi-line comments have been used since Chrome appears to be removing all line-breaks from bookmarklets (or something))
javascript:
var s = document.createElement('script');
s.setAttribute('src', 'http://example.com/ZeroClipboard.js');
s.onload = s.onreadystatechange =
function()
{
ZeroClipboard.setMoviePath( 'http://example.com/ZeroClipboard.swf');
var clip = new ZeroClipboard.Client();
/* glue to the body: sample only, in reality we should
probably create a new visible element and glue to that. */
clip.glue(document.body);
clip.setHandCursor( true );
/* copy to clipboard on mouse-up */
clip.addEventListener('onMouseUp',
function (client)
{
/* example */
var toCopy = document.title;
clip.setText(toCopy);
alert(toCopy + ' copied.');
clip.hide();
});
};
document.body.appendChild(s);
A couple disclaimers:
I'm not trying to spam you
I gain nothing if you choose to use this
I made a bookmarklet generator a while back to make it easier for me to create bookmarklets.
It's jQuery enabled, but that doesn't mean you have to use jQuery.
You can check out the source to see how to import another script/library into a page via a bookmarklet.
In particular, the lines that import jQuery:
if (!window.zbooks)
{
//if zbooks hasn't been set, initialize it
//s used for the Script element
var s = document.createElement('script');
//r used for the Ready state
var r = false;
//set the script to the latest version of jQuery
s.setAttribute('src', 'http://code.jquery.com/jquery-latest.min.js');
//set the load/readystate events
s.onload = s.onreadystatechange = function()
{
/**
* LOAD/READYSTATE LOGIC
* execute if the script hasn't been ready yet and:
* - the ready state isn't set
* - the ready state is complete
* - note: readyState == 'loaded' executes before the script gets called so
* we skip this event because it wouldn't have loaded the init event yet.
*/
if ( !r && (!this.readyState || this.readyState == 'complete' ) )
{
//set the ready flag to true to keep the event from initializing again
r = true;
//prevent jQuery conflicts by placing jQuery in the zbooks object
window.zbooks = {'jQuery':jQuery.noConflict()};
//make a new zbook
window.zbooks[n] = new zbooks(c);
}
};
//append the jQuery script to the body
b.appendChild(s);
}
I hope that helps.
A solution for both HTTP and HTTPS contexts
The Clipboard API solution by #Joachim Lous was on the right track for me. However, this did not work on localhost, which used http not https. To get around this, I used a "copyToClipboard" function (adapted from this SO answer) which acts as an all-in-one wrapper function that takes into account a http context by using a clever "out of viewport hidden text area" trick.
Readable version:
javascript:
function copyToClipboard(textToCopy) {
// navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard api method
return navigator.clipboard.writeText(textToCopy);
} else {
// use the 'out of viewport hidden text area' trick
let textArea = document.createElement("textarea");
textArea.value = textToCopy;
// make the textarea out of viewport
textArea.style.position = "fixed";
textArea.style.left = "-999999px";
textArea.style.top = "-999999px";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
return new Promise((res, rej) => {
// here the magic happens
document.execCommand('copy') ? res() : rej();
textArea.remove();
});
}
};
var element = document.querySelector(".myClass");
var text = element.textContent || element.value;
copyToClipboard(text);
Simply replace ".myClass" with your selector.
Minified version for bookmarklet:
javascript:void function(){var a=document.querySelector(".myClass"),b=a.textContent||a.value;(function(a){if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(a);else{let b=document.createElement("textarea");return b.value=a,b.style.position="fixed",b.style.left="-999999px",b.style.top="-999999px",document.body.appendChild(b),b.focus(),b.select(),new Promise((a,c)=>{document.execCommand("copy")?a():c(),b.remove()})}})(b)}();
Edit:
The following is a solution for those interested in dynamically selecting text from a page.
javascript:void function(){function a(a){if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(a);else{let b=document.createElement("textarea");return b.value=a,b.style.position="fixed",b.style.left="-999999px",b.style.top="-999999px",document.body.appendChild(b),b.focus(),b.select(),new Promise((a,c)=>{document.execCommand("copy")?a():c(),b.remove()})}}function b(a){c.style.pointerEvents="none";var b=document.elementFromPoint(a.clientX,a.clientY);return c.style.pointerEvents="auto",b}var c=document.createElement("div");Object.assign(c.style,{position:"fixed",top:0,left:0,width:"100vw",height:"100vh",zIndex:99999999,background:"transparent",cursor:"crosshair"}),document.body.append(c);document.addEventListener("mousemove",function(a){var d=b(a);if(d){var e=d.getBoundingClientRect();Object.assign(c.style,{background:"rgba(0, 128, 255, 0.25)",outline:"1px solid rgba(0, 128, 255, 0.5)",top:""+e.top+"px",left:""+e.left+"px",width:""+e.width+"px",height:""+e.height+"px"})}}),c.addEventListener("click",function(d){var e=b(d),f=e.textContent||e.value;f=f.replace(/\n[ \n]+\n/g,"\n").replace(/\n\n+/g,"\n\n").replace(/^\n+|\n+$/g,""),f.match("\n")||(f=f.replace(/^ +| +$/,"")),a(f),document.body.removeChild(c)})}();
Simply copy and paste it to the "URL" portion of your bookmark as shown below:
Is there a simple and reliable way to determine the URL of the currently-executing JavaScript file (inside a web page)?
My only thought on this is to scan the DOM for all the script src attributes to find how the current file was referenced and then figure out the absolute URL by applying it to document.location. Anyone have other ideas, is there some super-easy method I completely overlooked?
UPDATE: Script elements accessed via the DOM already have a src property which contains the full URL. I don't know how ubiquitous/standard that is, but alternatively you can use getAttribute("src") which will return whatever raw attribute value is in the [X]HTML.
Put this in the js file that needs to know it's own url.
Fully Qualified (eg http://www.example.com/js/main.js):
var scriptSource = (function(scripts) {
var scripts = document.getElementsByTagName('script'),
script = scripts[scripts.length - 1];
if (script.getAttribute.length !== undefined) {
return script.src
}
return script.getAttribute('src', -1)
}());
Or
As it appears in source (eg /js/main.js):
var scriptSource = (function() {
var scripts = document.getElementsByTagName('script'),
script = scripts[scripts.length - 1];
if (script.getAttribute.length !== undefined) {
return script.getAttribute('src')
}
return script.getAttribute('src', 2)
}());
See http://www.glennjones.net/Post/809/getAttributehrefbug.htm for explanation of the getAttribute parameter being used (it's an IE bug).
For recent browsers, you can use document.currentScript to get this information.
var mySource = document.currentScript.src;
The upside is that it's more reliable for scripts that are loaded asynchronously. The downside is that it's not, as best I know, universally supported. It should work on Chrome >= 29, FireFox >= 4, Opera >= 16. Like many useful things, it doesn't seem to work in IE.
When I need to get a script path, I check to see if document.currentScript is defined, and, if not, use the method described in the accepted answer.
if (document.currentScript) {
mySource = document.currentScript.src;
} else {
// code omitted for brevity
}
https://developer.mozilla.org/en-US/docs/Web/API/document.currentScript
As it appears in source (e.g. /js/main.js), this is cross-browser:
var scriptSource = (function()
{
var scripts = document.getElementsByTagName('script'),
script = scripts[scripts.length - 1];
//No need to perform the same test we do for the Fully Qualified
return script.getAttribute('src', 2); //this works in all browser even in FF/Chrome/Safari
}());
Fully Qualified (e.g. http://www.example.com/js/main.js):
After some tests it seems hard to get the fully qualified one in a cross-browser way. The solution suggested by Crescent Fresh does not work in IE8 to get the fully qualified, even if it works in IE7
This method work with defer, async and lazy loading
Since you know the filename of your script, and if it will be unique
/* see
* http://stackoverflow.com/questions/984510/what-is-my-script-src-url/984656#984656
* http://www.glennjones.net/Post/809/getAttributehrefbug.htm
*
* iterate all script to find script with right filename
* this work with async and defer (but your script MUST have a unique filemane)
* mozilla support document.currentScript and we use it, if is set
*
* this will not work with local script loaded by jQuery.getScript(),
* since there is no script tag added into the dom. the script is only evaluated in global space.
* http://api.jquery.com/jQuery.getScript/
*
* to fix this odd, you can add a reference in meta ( meta[name=srcipt][content=url] )
* when you load the script
*/
var scriptFilename = 'jquery.plugins.template.js'; // don't forget to set the filename
var scriptUrl = (function() {
if (document.currentScript) { // support defer & async (mozilla only)
return document.currentScript.src;
} else {
var ls,s;
var getSrc = function (ls, attr) {
var i, l = ls.length, nf, s;
for (i = 0; i < l; i++) {
s = null;
if (ls[i].getAttribute.length !== undefined) {
s = ls[i].getAttribute(attr, 2);
}
if (!s) continue; // tag with no src
nf = s;
nf = nf.split('?')[0].split('/').pop(); // get script filename
if (nf === scriptFilename) {
return s;
}
}
};
ls = document.getElementsByTagName('script');
s = getSrc(ls, 'src');
if ( !s ) { // search reference of script loaded by jQuery.getScript() in meta[name=srcipt][content=url]
ls = document.getElementsByTagName('meta');
s = getSrc(ls, 'content');
}
if ( s ) return s;
}
return '';
})();
var scriptPath = scriptUrl.substring(0, scriptUrl.lastIndexOf('/'))+"/";
a jquery plugin template with it:
https://github.com/mkdgs/mkdgs-snippet/blob/master/javascript/jquery.plugins.template.js
note: this will not work with local script loaded by jQuery.getScript(), since there is no script tag added into the dom. the script is only evaluated in global space.
http://api.jquery.com/jQuery.getScript/
to fix it you can do something like:
function loadScript(url,callback) {
if ( $('[src="'+url+'"]').length ) return true; // is already loaded
// make a reference of the loaded script
if ( $('meta[content="'+url+'"]', $("head")).length ) return true; // is already loaded
var meta = document.createElement('meta');
meta.content = url;
meta.name = 'script';
$("head").append(meta);
return $.ajax({
cache: true,
url: u,
dataType: 'script',
async: false,
success : function (script) {
try {
if ( typeof callback == 'function' ) callback();
} catch (error) {
//console.log(error);
}
}
});
}
If this is a strictly client solution, yours sounds pretty good.
If you are writing code on the server, you could probably just populate a div/hidden field/(insert your fave HTML element here) with the fully resolved URL to the script, and pick that up with your javascript on the clientside.
You may want to have a look at https://addons.mozilla.org/en-US/firefox/addon/10345 if you're interested in learning which functions (and thus which file) are executing on a page you don't control.
If you're interested in figuring out which of your scripts is executing, then there are a number of ways. With Firebug you could console.log() the information. Even just putting alert statements in your code (while annoying) can help debug in a low-tech way. You could also raise errors and catch them, then process using properties of the error (see: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Error)
However, why would this be important? If the script is causing errors already then it's easy enough to determine where the error is occurring. If it's not about errors at all, then what's the advantage in knowing which file it comes from?
I know this is a common requirement and there are lots of answers out in the wild. I would really appreciate if someone can provide a correct script which opens only external links from an HTML file in a new window.
You can use jQuery for this:
$(document).ready(function(){
$("a[href^='http']:not([href*='"+location.hostname+"'])").attr("target","_blank");
});
It should match both http and https links.
I use a little JavaScript on my own site. I then have a style setup to modify the link (it adds a little image/globe, vaguely MSDN like. Making the link open in a new page would also be trivial by modifying the target attribute.
if (document.links) {
for (var i = 0; i < document.links.length; i++) {
l = document.links[i].href;
if (l.indexOf('http://www.mysite.com')!=0 &&
l.indexOf('http://udv.mysite.com')!=0 &&
l.indexOf('http://')==0 ) {
c = document.links[i];
if (c.className == "dontModify") continue;
c.className = c.className + " external";
if (c.title != "") {
c.title = "External link: " + c.title;
}
}
}
}
The specific code is going to determine whether or not you use pure DOM-scripting, or any Javascript frameworks. But generally, here is what you'd do:
Set an onclick callback for all anchor.
In your callback, check to see if the href attribute of the link goes to an external site. You can use any number of ways to do this, but the easiest is probably a simple regex on the URL.
If not external, allow the link to progress as normal (i.e., return true and the like).
If external, open in new window, and then return false.
Opening a new window in Javascript is easy:
window.open('http://www.google.com');