Is It the Last 'Script' Element the Currently Running Script

Is it the last `script` element the currently running script?

It's not an absolute guarantee no. Check out this JSFiddle: http://jsfiddle.net/jAsek/

<!DOCTYPE html>
<title>Test case</title>
<div>
<p>At the start</p>
<script id="first">
var scr1 = document.createElement("script");
scr1.setAttribute("id", "early");
document.body.appendChild(scr1);
</script>
<p>After the first script</p>
<script id="second">
function getCurrentScriptElement() {
var scripts = document.getElementsByTagName('script');
return scripts[scripts.length - 1];
}

alert(getCurrentScriptElement().id);
</script>
<p>At the end</p>
</div>

Here the alert reports the id of the injected script "early", not the id of currently running script "second".

There's no practical difference between internal and external scripts.

Can you select the script element that included the JavaScript?

I'm hesitant to answer my own question in this case because I don't have an answer that works 100% of the time, but I've ironed out the bugs enough to have a stable solution.

@Shef's answer is halfway to what I wanted/needed.

Generic JS Version:

function getActiveScript()
{
var s;
s=document.getElementsByTagName('script');
return s[s.length - 1];
}

The issue with the above code is that it will select the last script on the page no matter when it was executed. This is a major issue if the calling script was included after page load.

As I can't directly select the script element (unless another solution presents itself), I'd rather not select anything if the script is being added after page load.

Pure JS Answer:

function getActiveScript()
{
var r,s;
r = document.readyState;
if ( r && r != 'complete' )
{
s = document.getElementsByTagName('script');
return s.length ? s[s.length - 1] : null;
}
return;
}

In the new version, document.readyState is checked to make sure that the document hasn't finished loading. Additionally on browsers where document.readyState isn't used, it will fail out (I can't think of any browsers that don't use document.readyState these days).

One caveat to this solution is that it may be possible to dynamically insert a script element into an earlier part of the document, which then gets executed before document.readyState is 'complete'. If the script were to use this code, it could possibly be referencing the wrong script. I haven't checked this issue yet. Typically I add new script tags with document.body.appendChild (or equivalent in a library), so it's not that big an issue to me.

Another possible loophole is if a new script has been appended to document.body before getActiveScript has been called. Again, I haven't tested it, but it may mean that the last selected script evaluates to on that's different than the one being executed.


Actual Usage:

The question was asked of why I wanted to select the currently evaluating script element. Although "Because I can" would probably be understood, I did have a legitimate reason to want to use this feature/functionality/dirty-nasty-hack.

I created a (couple) jQuery plugin(s) to do what I originally wanted.

jQuery Plugin: jquery.activescript.js

(function($){
"use strict";
$.activeScript = function(){
var r;
r=document.readyState;
return r && r != 'complete' ? $('script:last') : $();
};
})(jQuery);

jQuery Plugin: jquery.activescript.plugin.js

by default works for jQuery UI

(function($){
"use strict";
var plugins,d,p,$p;
d = $.activeScript().data();
plugins = d.plugins || 'draggable droppable resizable selectable sortable accordion autocomplete button datepicker dialog progressbar slider tabs';
plugins=plugins.split(' ');
$(function(){
while(p=plugins.pop())
{
$p=$(d[p+'Selector']);
if ($p[p])$p[p]();
}
});
})(jQuery);

The way you'd use jquery.activescript.plugin.js is as follows:

<script type="text/javascript" src="jquery.activescript.plugin.js"
data-draggable-selector=".draggable.default"
data-droppable-selector=".droppable.default"
data-resizable-selector=".resizable.default"
data-selectable-selector=".selectable.default"
data-sortable-selector=".sortable.default"
data-accordion-selector=".accordion.default"
data-autocomplete-selector=".autocomplete.default"
data-button-selector=".button.default"
data-datepicker-selector=".datepicker.default"
data-dialog-selector=".dialog.default"
data-progressbar-selector=".progressbar.default"
data-slider-selector=".slider.default"
data-tabs-selector=".tabs.default"></script>

This would allow you to semantically tie in your default plugins to your page without having to muck about in a JS file. If non-defaults are needed, you should muck about in a JS file, so I haven't added any mechanism for specifying options (although a few plugins could really use it).

This same basic activescript mechanism could be used by standalone plugins to have an easier way of overriding defaults.

Getting the currently executing, dynamically appended, script tag

Since the executing script presumably "knows" the name it was loaded with the following should work:

for (var s, scripts = document.getElementsbyTagName ('script'), i = scripts.length; i--;)
if ((s = scripts[i]).src.indexOf ('scriptname.js') < 0 && s.id && !test (s.id)) {
alert ("Script " + s.src + " id " + s.id + " not yet processed");
}

jQuery Select current script tag

Outside the document ready method, just do $('script').last();:

<script type="text/javascript">
var currentScript = $('script').last();
$(document).ready( function(){
//Use the variable currentScript here
})
</script>

Or simply give an id to your script.



Related Topics



Leave a reply



Submit