XSLT+JavaScript: using classes - javascript

I'm trying to use classes in XSL (the 'msxsl:script' tag). But I get the 'Syntax error' message when debugging the file. Here's a simple code that I'm using:
function Test1(str)
{
this.str = str;
}
Test1.prototype.getStr = function()
{
return this.str;
}
function test()
{
var newTest1 = new Test1("some string");
return (newTest1.getStr());
}
If I insert the code to a aspx file and call the test function, everything works fine, without any error messages.
Is it possible to use classes in XSL?

It seems that there are some odd restrictions on what you can use at the top level of the script blocks, and that they won't allow the use of this in top-level functions. However, if you go one level deeper, some of these restrictions go away:
function MakeTest1()
{
function inner(s)
{
this.str = s;
}
inner.prototype.getStr = function()
{
return this.str;
}
return inner;
}
var Test1 = MakeTest1();
function test()
{
var newTest1 = new Test1("some string");
return (newTest1.getStr());
}

Related

Try-catch block on multiple independent statements

Such that if one statement generates an error I want to keep the flow of execution.
I don't want to make as many try catch blocks as statements.
here is an example:
try {
a = results['a'].data();
b = results['b'].data();
c = results['c'].data();
d = results['d'].data();
} catch (e) {
}
In this case, data are to be retrieved from a dictionary, so whenever the key is undefined, calling data() generates an exception.
Catching which statement generates the exception, or making dummy booleans after each statement and dealing with the rest in final block seems much of a burden to me.
Using JavaScript as a language.
Try this:
;(function(fu){
a = fu(results,'a', null/*optional default value (for when is not exists)*/);
b = fu(results,'b');
c = fu(results,'c');
d = fu(results,'d');
//Other Codes...
})(function (r, n, def){return ((r[n]||{}).data||function(){return def;})();});
You should write a wrapper function to do that.
Lets name that function getData for example.
Your code would be like this:
// Dummy data
var results = {
"a": {
"data": function() {
return "Hello World";
}
}
};
a = getData(results['a'])
b = getData(results['b'])
c = getData(results['c'])
d = getData(results['d'])
function getData(result) {
try {
return result.data();
} catch (e) {
}
}

Closure compiler export Typescript classes and functions

I am trying to use closure compiler advanced mode on typescript generated classes with no success. Is there anyone who has accomplished such things.
Typescript Class
class TestData {
BlogName: string;
CacheTimeOut: number;
CopyrightHolder: string;
constructor(blogName: string, cacheTimeOut: number, copyrightHolder: string) {
this.BlogName = blogName;
this.CacheTimeOut = cacheTimeOut;
this.CopyrightHolder = copyrightHolder;
}
addBlog(value: string): boolean {
console.log('add blog');
return true;
}
validate(): boolean {
console.log('all valid');
return true
}
}
var myTestData = new TestData("name",22,"cpyright");
Generated Code
var TestData = (function () {
function TestData(blogName, cacheTimeOut, copyrightHolder) {
this.BlogName = blogName;
this.CacheTimeOut = cacheTimeOut;
this.CopyrightHolder = copyrightHolder;
}
TestData.prototype.addBlog = function (value) {
console.log('add blog');
return true;
};
TestData.prototype.validate = function () {
console.log('all valid');
return true;
};
return TestData;
})();var myTestData = new TestData();
This compiles into
new function() {};
I understand I should provide exports, so I added
window['TestData'] = TestData;
window['TestData'].prototype['addBlog'] = TestData.prototype.addBlog
window['TestData'].prototype['validate'] = TestData.prototype.validate
my output from closure compiler advanced compilation is
var a = function() {
function b() {
}
b.prototype.a = function() {
console.log("add blog");
return !0;
};
b.prototype.b = function() {
console.log("all valid");
return !0;
};
return b;
}();
window.TestData = a;
window.TestData.prototype.addBlog = a.prototype.a;
window.TestData.prototype.validate = a.prototype.b;
new a;
If you see there is still no constructor code that is left. This gets worse when we add this inside a module.
I also tried to use the #export of google closure wiht no success
I see couple of pluggins which can generate closure compiler annotations based on typescript, but those also doesnt generate proper code.
Thirdparty closure annotations generator
I ran a very basic test of this. Perhaps you changed your code and haven't re-tried.
If you compile the TypeScript in your question, it should result in the following JavaScript:
var TestData = (function () {
function TestData(blogName, cacheTimeOut, copyrightHolder) {
this.BlogName = blogName;
this.CacheTimeOut = cacheTimeOut;
this.CopyrightHolder = copyrightHolder;
}
TestData.prototype.addBlog = function (value) {
console.log('add blog');
return true;
};
TestData.prototype.validate = function () {
console.log('all valid');
return true;
};
return TestData;
})();
var myTestData = new TestData("name", 22, "cpyright");
In particular, the last line passes arguments to the TestData constructor.
A quick run of this results in (white-space is mine) using #compilation_level SIMPLE_OPTIMIZATIONS:
var TestData=function(){
function a(a,b,c){
this.BlogName=a;this.CacheTimeOut=b;this.CopyrightHolder=c
}
a.prototype.addBlog=function(a){console.log("add blog");return!0};
a.prototype.validate=function(){
console.log("all valid");return!0
};
return a
}(),myTestData=new TestData("name",22,"cpyright");
If you use advanced optimizations on partial code, it will be too aggressive. You need to supply all of your code for the Closure compiler to understand what really isn't used.
If your example represents all of your code, you'll notice that the constructor along with all three properties (BlogName, CacheTimeOut, and CopyrightHolder) are genuinely never used, so can be removed without affecting the behaviour of the program.
Answer: optimized noops are - wait for it - noops :)
Explanation:
If you use your gen code here http://www.closure-compiler.appspot.com/home
with ADVANCED_OPTIMIZATIONS it produces:
new function(){};
if you add myTestData.addBlog("test"); it produces:
(new (function(){function a(){}a.prototype.a=function(){console.log("add blog")};return a}())).a();

Javascript concatenate a function similar to how text can be added

In javscript we can do this
var text = "the original text";
text+=";Add this on";
If a library has a function already defined (e.g)
//In the js library
library.somefunction = function() {...};
Is there a way to add something on so that I can have two functions run?
var myfunction = function() {...};
Something like:
library.somefunction += myfunction
So that both myfunction() and the original library.somefunction() are both run?
You can use this kind of code (leave scope empty to use default scope):
var createSequence = function(originalFn, newFn, scope) {
if (!newFn) {
return originalFn;
}
else {
return function() {
var result = originalFn.apply(scope || this, arguments);
newFn.apply(scope || this, arguments);
return result;
};
}
}
Then:
var sequence = createSequence(library.somefunction, myFunction);
I think what you want to create is a Hook (function) - you want to call library.somefunction but add a bit of your own code to run before. If that's the case, you can make your myfunction either call or return the library function after it's done with your bit of code.
var myfunction = function() {
// your code
// ...
return library.somefunction();
}

How to use prototype for custom methods and object manipulation

Honestly, I am trying to understand JavaScript prototypes and I'm not making much progress. I am not exactly sure how to explain what I am trying to do, except to say that in part my end goal is to learn how to traverse the DOM similar to jQuery and to add custom methods to manipulate particular elements being accessed.
EDIT : The code below has been updated to reflect concepts I have learned from the answers received so far, and to show where those fall short of what I am looking to accomplish.
function A(id) {
"use strict";
this.elem = document.getElementById(id);
}
A.prototype.insert = function (text) {
"use strict";
this.elem.innerHTML = text;
};
var $A = function (id) {
"use strict";
return new A(id);
};
var $B = function (id) {
"use strict";
return document.getElementById(id);
};
function init() {
"use strict";
$A('para1').insert('text goes here'); //this works
$A('para1').innerHTML = 'text goes here'; //this does not work
console.log($A('para1')); //returns the object A from which $A was constructed
console.log($B('para1')); //returns the dom element... this is what I want
/*I want to have $A('para1').insert(''); work and $A('para1').innerHTML = '';
work the same way that $B('para1').innerHTML = ''; works and still be able
to add additional properties and methods down the road that will be able
act directly on the DOM element that is contained as $A(id) while also
being able to use the properties and methods already available within
JavaScript*/
}
window.onload = init;
Where possible please add an explanation of why your code works and why you believe it is the best possible method for accomplishing this.
Note: The whole purpose of my inquiry is to learn this on my own... please do not suggest using jQuery, it defeats the purpose.
var $ = function(id) {
return new My_jquery(id);
}
function My_jquery(id) {
this.elem = document.getElementById(id);
}
My_jquery.prototype = {
insert : function(text) { this.elem.innerHtml = text; return this;}
}
$('para1').insert('hello world').insert('chaining works too');
add any method u want to operate on elem in My_jquery.prototype
You can use a scheme like the following:
function $(id) {
return new DOMNode(id);
}
function DOMNode(id) {
this.element = document.getElementById(id);
}
DOMNode.prototype.insert = function(value) {
if (value) {
// If value is a string, assume its markup
if (typeof value == 'string') {
this.element.innerHTML = value;
// Otherwise assume it's an object
} else {
// If it's a DOM object
if (typeof value.nodeName == 'string') {
this.element.appendChild(value);
// If it's a DOMNode object
} else if (this.constructor == DOMNode) {
this.element.appendChild(value.element);
}
}
} // If all fails, do nothing
}
$('id').insert('foo bar');
Some play stuff:
<div id="d0">d0</div>
<div id="d1">d1</div>
<div id="d2">d2</div>
<script>
// insert (replace content with) string, may or may not be HTML
$('d0').insert('<b>foo bar</b>');
// insert DOMNode object
$('d0').insert($('d1'));
// Insert DOM element
$('d0').insert(document.getElementById('d2'));
</script>
You may find it useful to study how MyLibrary works, it has some very good practices and patterns.
Try this.
var getDOM= function(id) {
this.element= document.getElementById(id);
}
getDOM.prototype.insert= function(content) {
this.element.innerHTML= content;
}
var $= function(id) {
return new getDOM(id);
};
$('id').insert('Hello World!'); // can now insert 'Hello World!' into document.getElementById('id')

Insert and execute javascript

I have a javascript variable:
var foo='<script type="text/javascript">alert("Hello World");<\/script>'
The variable is inserted with element.innerHTML=foo; after an event occurs on the page, about 10 seconds after the page is loaded.
Is there a way to execute the 'alert' function right after the insertion?
If you absolutely, positively have to take JavaScript code that's in a string and execute it, you basically have to use eval or an eval-like mechanism. In some years of JavaScript programming, I've never had to resort to it, and I do suggest that you look at whether there's another way to achieve your actual overall goal.
So here, you'd strip off the script tag stuff and just eval the code, e.g.:
var script = foo.replace(/^<script[^>]*>/, "").replace(/<\/script>$/, "");
eval(script);
// Or window.evalInGlobalScope(script); // -- See below
Obviously you have to be sure you trust the source of the string, since you're executing the code therein.
eval is a slippery beast and plays very odd games with context and scope. If you need something that looks more like what you'd get if you did add a script tag to the page, here's a function that does that cross-browser (from my answer to this other question here on Stack Overflow):
window.evalInGlobalScope = (function() {
var fname, scr;
// Get a unique function name
do {
fname = "__eval_in_global_test_" + Math.floor(Math.random() * 100000);
}
while (typeof window[fname] !== 'undefined');
// Create test script
scr = "function " + fname + "() { }";
// Return the first function that works:
return test(evalInGlobalScope_execScript) ||
test(evalInGlobalScope_windowEval) ||
test(evalInGlobalScope_theHardWay) ||
evalInGlobalScope_fail;
function test(f) {
try {
f(scr);
if (typeof window[fname] === 'function') {
return f;
}
}
catch (e) {
return false;
}
finally {
try { delete window[fname]; } catch (e) { window[fname] = undefined; }
}
}
function evalInGlobalScope_execScript(str) {
window.execScript(str);
}
function evalInGlobalScope_windowEval(str) {
window.eval(str);
}
function evalInGlobalScope_theHardWay(str) {
var parent, script, d = document;
parent = d.body || d.documentElement || d.getElementsByTagName('head')[0];
if (parent) {
script = d.createElement('script');
script.appendChild(d.createTextNode(str));
parent.appendChild(script);
}
}
function evalInGlobalScope_fail() {
throw "evalInGlobalScope: Unable to determine how to do global eval in this environment";
}
})();
Live example using the above
You don't need to make lots of changes, just one small change.
Right now you have such line of code:
oDiv.innerHTML = foo;
Just change it to those three lines instead:
var oScript = document.createElement("script");
oScript.innerHTML = foo;
oDiv.appendChild(oScript);
And have foo contain only the raw JS, without the <script> and </script> tags.
Live text case.

Categories

Resources