[IDEA] plusQuery |
Author: |
Message: |
Matti
Elite Member
Script Developer and Helper
Posts: 1646 Reputation: 39
32 / /
Joined: Apr 2004
|
RE: [IDEA] plusQuery
The solution I came up with also uses eval() as there's no global object in JScript which stores the global variables. (In browser JavaScript, there's the global object "window" which holds the global scope.)
However, you'll have to do one extra thing to make it work...
When adding globals using eval() in run-time, the scripting engine will not register those added functions as event handlers. That is, if you add an OnWndIdEvent_Destroyed() event using eval(), it won't get called when the window is destroyed. The trick to get these registered is to use MsgPlus.LoadScriptFile(). When calling LoadScriptFile, the script file is loaded and the global scope is rescanned for event handlers. This results in the newly added functions to be properly registered.
Note that you don't need to trick eval() to be called in the global scope. By simply omitting the "var" keyword, the variable will be created in the global scope. It is generally a bad idea to omit the "var" keyword, but in this case it's sort of acceptable.
Proof of concept:
Javascript code:
var plusWnd = $(MsgPlus).CreateWnd("interface.xml", "yiew", 0);
//[...]
$.wrappers.MsgPlus.CreateWnd = function (XmlFile, WindowId, Options) {
var toEval = "On" + WindowId + "Event_Cancel = function (plusWnd) { $.trigger(plusWnd, '" + WindowId + "Event_Cancel', plusQuery.$A(arguments)); };";
toEval += "On" + WindowId + "Event_Destroyed = function (plusWnd, exitCode) { $.trigger(plusWnd, '" + WindowId + "Event_Destroyed', plusQuery.$A(arguments)); };";
//etc
eval(toEval);
$(MsgPlus).LoadScriptFile("_blank.js"); // black magic happens here
this.original.CreateWnd(XmlFile, WindowId, Options);
}
The loaded script file can contain anything. From my tests, it may not be completely empty though - one character will work though. I think the best options to fill this file with are a single space " " or a semicolon ";". You can even save it as ANSI and save a few bytes, Plus! will still parse it (although Plus! recommends Unicode).
I warned you, it's very hackish and not really recommended (eval is evil but so is LoadScriptFile) but unfortunately it's the only way I could get this to work. Feel free to use it if you think it's "good enough" but think about the consequences. If you decide to use this, don't forget to keep track of the created event handlers so you don't need to redeclare them when creating the same window twice.
This post was edited on 04-06-2011 at 03:05 PM by Matti.
|
|
04-06-2011 03:03 PM |
|
|
Amec
Junior Member
Posts: 19
33 / /
Joined: Sep 2008
|
O.P. RE: RE: [IDEA] plusQuery
quote: Originally posted by Matti
there's no global object in JScript
This is REALLY annoying... Surely they could switch to V8 or something? But then they'd have to write their own stuff for accessing ActiveX... Hmm.
quote: Originally posted by Matti
Note that you don't need to trick eval() to be called in the global scope. By simply omitting the "var" keyword, the variable will be created in the global scope. It is generally a bad idea to omit the "var" keyword, but in this case it's sort of acceptable.
It's not really "tricking eval"... It's fine, and more clear than just declaring the variables without var. And what happens if there's a variable with the same name in the local scope? (I know that'll almost never happen, but still)
Now that I think about it... Wouldn't there be a message to MessengerPlusLive_MsgPump we could send to have the script reevaluated? Not 0x81CE, (restarts all scripts) but something similar?
|
|
04-06-2011 04:11 PM |
|
|
matty
Scripting Guru
Posts: 8336 Reputation: 109
39 / /
Joined: Dec 2002
Status: Away
|
RE: [IDEA] plusQuery
One thing I noticed
Javascript code:
$.addEventListener("ChatWndReceiveMessage", function (chatWnd, origin, message, msgKind) {
if (msgKind === 1)
{
$.triggerCommand($(chatWnd), $(chatWnd.Contacts).GetContact(origin), message.split(' ')[0].toUpperCase(), message.split(' ').slice(1).join(' '), message, true);
}
});
You cannot obtain the Contact object by passing the origin parameter to the GetContact function.
This post was edited on 04-06-2011 at 05:27 PM by matty.
|
|
04-06-2011 05:19 PM |
|
|
Eljay
Elite Member
:O
Posts: 2949 Reputation: 77
– / / –
Joined: May 2004
|
RE: [IDEA] plusQuery
JScript does have a global scope. In regular JScript (WSH) you can just do "var global = this" in global scope then access it anywhere.
It definitely worked at some point, but use of it was removed/broken by Plus! in an update to the scripting engine.
I'm sure there was a reason but I sure as hell can't remember it Maybe something to do with the event handling.
I know it worked because I made a script that allowed you to hook events or something like that, and my script broke
Edit: found it [Beta-ish Utility Release] Hook System
So it was broken at some point between 2006 and now, lol.
This post was edited on 04-06-2011 at 06:12 PM by Eljay.
|
|
04-06-2011 06:03 PM |
|
|
Matti
Elite Member
Script Developer and Helper
Posts: 1646 Reputation: 39
32 / /
Joined: Apr 2004
|
RE: [IDEA] plusQuery
quote: Originally posted by matty
One thing I noticed
You cannot obtain the Contact object by passing the origin parameter to the GetContact function.
He extended the GetContact implementation so that you can search by name as well.
Javascript code:
$.wrappers.Contacts.prototype.extend({
GetContact: function (str) {
if (str.toLowerCase() === Messenger.MyEmail.toLowerCase()) {
return this[0];
} else if (this.original.GetContact(str)) {
return $(this.original.GetContact(str));
} else {
for (var i = 0; i < this.length; i++) {
if (this[i].Name === str) {
return this[i]; // Only returns the first match
}
}
}
return null;
}
});
Still, it's not a good idea to do this. The value of origin may not resolve to the right contact, for example when a contact has a nickname assigned. Contact.Name always returns the name as published by the contact, whereas origin may contain the nickname of that contact. I think it's better to simply use origin - if the developer wants to resolve this to a contact, he can just implement this in the callback or override the event himself.
Also, the local command parsing should be a bit more sophisticated. For example, script commands should be escapable by adding an extra leading slash, such as "//mycommand". Also, parameters can be separated by many sorts of whitespace characters such as \n, \r,... Therefore, you'll need a regular expression to properly detect whether a given message is a script command and correctly separate the command from the parameter. Luckily, Cookie has written an excellent regular expression for this: CookieRevised's reply to Gettin data from "/" commands.
The way I parse local commands is based upon Cookie's regular expression but instead of using the global RegExp object to retrieve the data, I use the result from exec() itself. It's better to use your local data rather than having to rely on global side effects.
Javascript code:
var match = /^\/([^ \n\r\v\xA0\/][^ \n\r\v\xA0]*)(?:[ \n\r\v\xA0]([\s\S]*))?$/.exec(message);
if ( match ) {
var command = match[1]; // note: command will have no leading slash
var parameters = match[2];
var tmp = $.triggerCommand($(chatWnd), $.MyContact, command, parameters, message, false);
return (tmp === undefined ? message : tmp);
}
This principle can't be easily ported to external commands though, since you don't know what the leading character will be (! or @ or ...). However, you won't have to deal with escaped commands either. I'd recommend to simply look for the command until the first encountered whitespace character and use the remaining part as parameters.
Javascript code:
var match = /^([^ \n\r\v\xA0]*)[ \n\r\v\xA0]?([\s\S]*)$/.exec(sMessage);
if ( match ) {
var command = m[1]; // note: command will retain its leading character
var parameters = m[2];
$.triggerCommand($(chatWnd), $.MyContact, command, parameters, message, true);
}
quote: Originally posted by Eljay
JScript does have a global scope. In regular JScript (WSH) you can just do "var global = this" in global scope then access it anywhere.
I know, I tried that but it's inaccessible. You can't read global variables from it or add variables to it. Heck, you can't even iterate over its contents. Very sad indeed.
Long post is long indeed.
|
|
04-06-2011 06:11 PM |
|
|
Eljay
Elite Member
:O
Posts: 2949 Reputation: 77
– / / –
Joined: May 2004
|
RE: [IDEA] plusQuery
Ok I found when/why global scope was broken: Patchou's reply to 300 breaks NP script
It seems that when Patchou added the global enums (STATUS_BUSY, etc.), it broke the global scope
|
|
04-06-2011 06:20 PM |
|
|
CookieRevised
Elite Member
Posts: 15517 Reputation: 173
– / /
Joined: Jul 2003
Status: Away
|
RE: [IDEA] plusQuery
Offtopic sidenote: quote: Originally posted by Matti
The way I parse local commands is based upon Cookie's regular expression but instead of using the global RegExp object to retrieve the data, I use the result from exec() itself. It's better to use your local data rather than having to rely on global side effects.
It's not 'better' though (it isn't worse either for that matter). There is nothing wrong with using the global RegExp object as long as both functions (exec and the resulting global RegExp object) are used right after eachother. But if they are not used right after eachother, then yes, you have a very good point. But also, it is also not a 'side effect' though; the $1 identifiers are meant to be used like that.
But, this is just semantics I guess and what you prefer....
On topic, nice to see some advanced 'toying' (if I may use that word) with the scripting engine to create such a library and create such possebilities. But although I'm sure one could come up with an exotic use or examples for it, I must say, I can't see any real use of it in practice, certainly not for the average script and scripter, but also not for the more advanced scripts. But this said, again, great work .
.-= A 'frrrrrrrituurrr' for Wacky =-.
|
|
04-06-2011 10:27 PM |
|
|
Amec
Junior Member
Posts: 19
33 / /
Joined: Sep 2008
|
O.P. RE: [IDEA] plusQuery
quote: Originally posted by Matti
Another thing I noticed is that you're extending Object.prototype.
Fix'd. Moved all of those functions to plusQuery.
quote: Originally posted by Matti
Here's a suggestion: use combined getter/setter methods for the properties in the wrapper classes.
Done.
quote: Originally posted by Matti
Also, the local command parsing should be a bit more sophisticated.
Aaaand done!
What I haven't done:
- Implemented dynamic function binding for PlusWnd events. Not sure if I'm going to do this, yet... I'll have to test a lot before I decide.
- Changed GetContact so you can't search by name. Haven't decided what I'm gonna do with this one... It's so simple with it there, but I'm aware of the pitfalls... Perhaps... ChatWnd.GetContactByName and ChatWnd.GetContactByEmail? Dunno.
quote: Originally posted by Eljay
It seems that when Patchou added the global enums (STATUS_BUSY, etc.), it broke the global scope
Is he planning on fixing it? -_-
quote: Originally posted by CookieRevised
On topic, nice to see some advanced 'toying' (if I may use that word) with the scripting engine to create such a library and create such possebilities. But although I'm sure one could come up with an exotic use or examples for it, I must say, I can't see any real use of it in practice, certainly not for the average script and scripter, but also not for the more advanced scripts. But this said, again, great work .
I find it useful for writing my own small scripts. Here's a recent example: I wanted to add two commands, "/afk" and "/back", which set my name to Messenger.MyName + "\xA0" + status, and back again. Pretty simple, ey? So instead of creating a whole new script for it, I just created a new .js in my "Misc" script which has _plusquery.js, and added it using $.addCommand. Much easier/faster/better(?) than creating a whole new script and doing all the parsing of commands, etc. again.
|
|
04-07-2011 05:43 AM |
|
|
CookieRevised
Elite Member
Posts: 15517 Reputation: 173
– / /
Joined: Jul 2003
Status: Away
|
RE: [IDEA] plusQuery
Sure, but as for that specific example, that could be done in much easier ways too though I think (as in using a more straightforward library). So, maybe not the best example. But as long as you (and others) find it useful, then
.-= A 'frrrrrrrituurrr' for Wacky =-.
|
|
04-07-2011 09:36 AM |
|
|
Pages: (2):
« First
«
1
[ 2 ]
Last »
|
|
|