ID:1477869
 
Resolved
Winset and Winget can now be accessed via JavaScript in a browser control, allowing for more responsive interfaces. See the new section in the skin reference for details.
Applies to:Dream Seeker
Status: Resolved (504.1228)

This issue has been resolved.
I would most definitely like some means of actually telling DreamSeeker to directly invoke winsets from the local client using Javascript.

Obviously, this should be a per-browser optional toggle for browser elements.

Additionally, a winset command that invokes javascript on a browser in the interface would most definitely be useful for communication between different browser elements on the same interface.

That way I don't have to tell JS to tell DM to tell the interface to update whenever I'm changing something that's not in the browser.
We will look into a way for JS to communicate back to the server. This is actually something I've been thinking about independently for the web client.
We will look into a way for JS to communicate back to the server.

I'm not sure if you misspoke, Tom, but we've actually got a solid way to communicate back to the server already via forcibly invoking click events embedded in the html context via JS.

Basically, here's how I author a system like that:

Setting a hidden anchor href in the document you browse, and then getting the handle from document.getElementsById(), you can later call anchor.click() to forcibly invoke the method. If the href is set to an "?src=\ref[obj];args" format, this anchor element can be used as a generic function call in JS to trigger Topic() references.

I'm all for potentially being able to direct-invoke verbs and feed them arguments from JS, though. That would potentially speed up the javascript communication to/from the server quite a lot, rather than using Topic for everything.


So yeah, communication to a server from JS is not a problem at all, and wasn't the intent of this request.


However, what I was asking for specifically with this feature, was being able to invoke a verb or other command on the Seeker/Client that the browser has been displayed to.

Essenatially, from JS, I want to be able to do something like:

DreamSeeker.winset(control,params)
DreamSeeker.winget(control,params)
DreamSeeker.winhide(control)
DreamSeeker.verb(verbname,arg1,[...)


In addition, I would like to be able to communicate to other browsers from JS inside of one browser, but locally across the same client.

That way, if I have two browsers displayed to one DreamSeeker client, I can literally just do things like:

DreamSeeker.output(message,control)

And use the existing Javascript invocation method DM's output() already offers, just from within Javascript.



In all honesty, this puts us so close to client-side interface control that it's not even funny. Literally the only thing you wouldn't be able to do on the client-side is actually add screen objects to the viewport.

This would add so much legroom to the existing implementation of BYOND's browser elements that it wouldn't even be funny.
Ah, yeah I misunderstood. I was talking more about a built-in call to directly relay commands from HTML UI elements to the server without going through Topic(), although I suppose you are correct that this can all be hacked together currently.

So as far as javascript->client communication, it sounds to me like you want to be able to call the "." commands through javascript (mainly for .winset). So we would just need to add support to that in the byond:// protocol (maybe something like href="byond://.[winset/whatever]" or shorthand href=".[winset]". I think our browser component could then intercept that and deliver it to the client without sending it as as normal link to the server.
Tom wrote:

So as far as javascript->client communication, it sounds to me like you want to be able to call the "." commands through javascript (mainly for .winset). So we would just need to add support to that in the byond:// protocol (maybe something like href="byond://.[winset/whatever]" or shorthand href=".[winset]". I think our browser component could then intercept that and deliver it to the client without sending it as as normal link to the server.

Yes, that sounds fabulous. Just having access to winset() alone would be huge. Also, on the subject of winget(), I know you guys inject a bunch of JS into the browser that helps with some convenience functions and formatting standardization.

I figure one of the better ways to handle that would be literally injecting a global variable named winget() into the browser context. DS would, instead of passing the information relating to the interface back to the server halt processing in that browser's JS (haltProcessing(x)) until DS returned the requested information. It's ugly, but should work reasonably well considering it will only take a millisecond or two for the local DS to communicate with the local browser, right?

Am I assuming correctly that winget() would be less trivial, but still reasonable?

I was talking more about a built-in call to directly relay commands from HTML UI elements to the server without going through Topic(), although I suppose you are correct that this can all be hacked together currently.

That would be nice, but we'd absolutely have to be sure that client/mob verbs would be the only things we could call built-in without providing the browser a src reference and using the Topic() setup we currently use for communication.

The really key thing about this, is that it's kind of a must that the client/browser conversation looks something a bit more like this with select operations:

DS<->JS

We can currently go:

DM->DS->JS->DS->DM

Which is great, but I'm sure you can see the benefit of being able to back-and-forth with JS a bit more without the server being in on the conversation.

Thanks for considering this, Tom. This would be absurdly huge for getting some of the bloat off of the server, and making interfaces a lot more dynamic and interesting, much like the 500 update did for animations. I'm dirt poor at the moment, but I really need to toss some cash in the BYOND bank. Once my new job starts paying out, I'd really like to start making a monthly dent in that donation bar (and my car payment!).
I've implemented something for this and I'm getting in documentation for it. The upshot is that you now have special URLs to use via JavaScript in a browser control:

byond://winset?id=[id]&[property]=[value]&...
byond://winget?callback=[function name]&id=[id or list]&property=[id or list]

Set window.location to the URL and you'll be set; you'll want to use encodeURIComponent() for any text beyond letters, numbers, hyphens, commas, and periods. The winget version supports comma-separated lists of IDs and/or properties, and window.* is still supported as an ID.

The winget callback function that you write takes a JavaScript object as the only argument; it might for example be something like {size:'500x500'}.
And this operates completely on the client-side without any communication to the server?

I could kiss you right now, Lummox, Tom. That callback is going to make designing functions a bit tougher, but it's absolutely better than not having it at all.

The only way to make it better would be via a compact webkit browser implementation, but it's already Christmas for me right now, so asking for more would just be greedy.

Cheers! I'll be putting this to good use.
Yes, this doesn't interact with the server. It mirrors the .winset command-line function (which can be relayed from skin controls, and now from JS).
In response to Tom
Tom wrote:
Yes, this doesn't interact with the server. It mirrors the .winset command-line function (which can be relayed from skin controls, and now from JS).

This was an amazing turnaround. Thank you.
Lummox JR resolved issue with message:
Winset and Winget can now be accessed via JavaScript in a browser control, allowing for more responsive interfaces. See the new section in the skin reference for details.
Holy shit, am I late to the party, or what!? This is freaking awesome.
I don't know why you are so excited about this. You can't guarantee that every user will even have JavaScript enabled, so how can you rely on it? It would be nice if BYOND had its own built-in client-side scripting language that was guaranteed to work with every client.

This is still kind of good because at least it can speed up games for every client that does happen to have JavaScript enabled, but this doesn't make DM any less of a server-side language.
Well, you're odds on in favour of javascript being enabled. Like .... majorly odds on.
Will there be some documentation on this, for our members who are not too good with JS.
In response to Multiverse7
Multiverse7 wrote:
I don't know why you are so excited about this. You can't guarantee that every user will even have JavaScript enabled, so how can you rely on it?

Stephen001 wrote:
Well, you're odds on in favour of javascript being enabled. Like .... majorly odds on.

To reiterate this point, the engine that BYOND uses to render the browser element is that of Internet Explorer 7 Embedded, or the compatibility mode from a newer version. I can guarantee you that 99% of people who aren't developers have no idea what that is, let alone how to change settings for it. And can guess what is enabled by default? That's right: JavaScript.

Pretty much all of the compatibility issues I've encountered came from a botched update package that Microsoft released. Only the most recent version of Internet Explorer has an incompatibility with my projects is the most recent version and that is only with one set of variables that were modified recently for security reasons.

EDIT: Though upon further research, this seems to be a change that was released accidentally or was otherwise backtracked. Odd.
In response to Multiverse7
Multiverse7 wrote:
You can't guarantee that every user will even have JavaScript enabled, so how can you rely on it?

world
mob = /mob/initial_login

mob/initial_login
Login()
var/browser_test/t = new/browser_test(src)
. = t.connect()
if(.)
var/mob/m = new/mob/actual_login()
m.key = src.key
del src

mob/actual_login
Login()
//put your real login code here

var/confirm_page = {"<HTML><BODY></BODY></HTML><SCRIPT type="text/javascript">[INSERT THE JAVASCRIPT HERE]</SCRIPT>"}

browser_test
var
mob/owner
waiting = 0
proc
connect()
if(waiting) return
waiting = 1
var/sendcount = 0
var/threshold = 10
while(waiting&&threshold<=40)
owner << browse(confirm_page,"window=confirmbrowser;display=1")
while(waiting && ++sendcount<=threshold)
owner << output("\ref[src]","confirmbrowser:commref")
sleep(1)
threshold *= 2
sendcount = 0
if(waiting)
waiting = 0
owner << "Your browser is not compatible with this game. Please enable Javascript and ensure you have Internet Exploder 7+. <a href=\"http://www.visualwalkthrough.web/\">Click here for details.</a>"
return 0
else
return 1
New(mob/m)
owner = m
Topic(href,href[])
if(href["command"]=="acknowledge")
waiting = 0


//this is actually javascript.

var __src;

//called internally via output() to change the src reference.
function commref(srcref) {
__src = "?src=" + srcref + ";";
Communicate("command=acknowledge;");
}

//communicate back to DM
function Communicate(msg) {
window.location = "byond://" + __src + msg;
}


There you go, ~5 minutes, and everybody who is logged into your game will have javascript enabled.

but this doesn't make DM any less of a server-side language.

Yes and no. A lot more can be done for interface-heavy games, but for games like NEStalgia, where the client-side frontend is almost entirely in the map element, this feature will mean effectively nothing.


But for a setup like this one
, this kind of thing will make more polished interfaces even easier to set up and manage via Javascript, and even optionally flash elements embedded in browsers.

Yeah, it'd be nice if the browser could be partially transparent. Yeah, it'd be nice if we could embed the map element IN a browser, rather than just over/under browsers, yeah, it'd be nice if we could write client-side code that would determine things like the positions of screen objects, and whatnot, but it's probably not going to happen in any foreseeable realistic future.

The two features I requested regarding JS make things like processing input/output entirely on the client-side possible. You can now call verbs directly from JS. You can now have asynchronous applications in JS running alongside your server that link into the gameworld.

There are a huge number of possibilities for something like this, and it really shouldn't be discounted. This is an opportunity to learn to write code almost like you are working on an actual game, and not just using a highly simplistic game engine. Best to use it.

--Yeah, I agree, we should have a webkit or chrome-based browser with HTML5 and a mountain of new possibilities, but it's just not happening at this moment, so we've got to stick with what we can feasibly do with this setup, which is quite a lot.
After finding that a particular user didn't have JavaScript enabled, I wouldn't prevent them from logging in, but instead warn them about a less than ideal experience, then dynamically reconfigure their interface to a kind of DM only compatibility mode.

It's just kind of painful to know that a simple language like JavaScript actually adds functionality to DM, the language of the BYOND game development engine. It's like some kind of bizarre symbiotic parasite.
Javascript is used with a lot of languages actually, as are other scripting languages like Lua. It's not uncommon at all.

And from what I've seen, even if you have javascript disabled in IE, it'll still work in the embedded browser.
In response to Jean Sqribe
Jean Sqribe wrote:
Will there be some documentation on this, for our members who are not too good with JS.

There is documentation on how to use the commands, but there are no example functions. If you're not good with JS chances are you won't be using these features anyway. But if you want some simple access functions for JS:

function winset(id, params) {
// params is an object
if(!params) params = {};
var encoded=[], url='byond://winset?';
if(id) encoded.push("id=" + encodeURIComponent(id));
for(var property in params) {
encoded.push(encodeURIComponent(property) + "=" + encodeURIComponent(params[property]));
}
url += encoded.join('&');
window.location = url;
}

var savedfuncs=[];
function winget(id, property, callback) {
// property is a string or array
var encoded=[], url='byond://winget?';
if(!property || !callback) return;
if(typeof callback != 'string') {
if(callback.name) callback = callback.name;
else if(callback.savedid !== undefined) callback = 'savedfuncs['+callback.savedid+']';
else {
callback.savedid = savedfuncs.length;
savedfuncs.push(callback);
callback = 'savedfuncs['+callback.savedid+']';
}
}
if(typeof property != 'string') {
if(!property.join) return;
property = property.join(',');
}
encoded.push('callback=' + encodeURIComponent(callback));
if(id) encoded.push('id=' + encodeURIComponent(id));
if(property) encoded.push('property=' + encodeURIComponent(property));
url += encoded.join('&');
window.location = url;
}


You're on your own for the callback function, though the values you get will be easy to work with. A quick rundown of the types you might encounter in a callback:

String/file: A string
Number: A number
Boolean: True or false
Size/position: Object with x and y properties (x=-1,y=-1 for "none" position)
Color: Object with properties red, green, blue, alpha, isDefault (if true), value (value used in BYOND skins), and css.
From ter's post 's the implications of this seem more than trivial. The issue is these things just get turned into a plug n play library down the line; doesn't allow for the less experienced guys to interact with the base code.

I have small experience in jquery, but that has so much documentation even my mum can learn it!

Yeah the target audience here needs that am mount of breast feeding :p
Page: 1 2