A closed system cannot be all things to all people
Three main approaches:
With a base document
<InputBindings> <KeyBinding Modifiers="Ctrl" Key="L" Command="Close" /> </InputBindings>
And overlay
<modify selector="InputBindings" where="after"> <KeyBinding Modifiers="Ctrl" Key="L" Command="GoToLocation" /> </modify>
What should happen when Ctrl+L is pressed?
(*adapted from real-world example)
Example: prototyping HTML5 concepts
Competing design goals:
How to support all of these?
Everything within the arrows is HTML
We don't have generated content yet…
but maybe we can use other mechanisms?
<overlay> <modify selector="head" where="after"> <self> <style> li > span { margin-right: 1em; } li > span { color: red; } li li > span { color: blue; } </style> </self> </modify> <modify selector="li" where="before"> <self> <span>•</span> </self> </modify> </overlay>
Only two mechanisms within JS:
var oldF = f; f = function(x, y) { doStuff(x,y); return oldF.apply(this, 2*x, y); };
eval("f = " + f.toString() .replace('x', '2*x'));
eval("XULBrowserWindow.setOverLink = " + XULBrowserWindow.setOverLink.toString().replace(/{/, "$& link = Fission.setOverLink(link);"));
function XULBrowserWindow.setOverlink(link) { link = Fission.setOverLink(link); … };
(*real-world example)
eval('window.aioTabFocus = '+window.aioTabFocus.toSource() .replace( /\{/, '{'+ 'if (e.originalTarget.ownerDocument != document)'+ 'return;'+ 'var b = e.originalTarget;'+ 'while (b.localName != "tabbrowser")'+ 'b = b.parentNode;' ).replace( /aioTabsNb/g, 'b.aioTabsNb' ).replace( /aioContent/g, 'b' ).replace( /aioRendering/g, '(b.mPanelContainer || b)' ) );
function foo(x) { return x*x; } var bar = foo; eval("foo = " + foo.toString().replace("x*x", "42")); # foo(5) == bar(5); # false
function onLoad(evt) { window.alert("hello"); } window.addEventListener("load", onLoad, …); eval("onLoad = " + onLoad.toString.replace('hello', 'hi there')); # …loading the page… # Alert: “hello”
function makeAdder(x) { return function(y){ return x+y; }; } var addFive = makeAdder(5); eval("addFive = " + addFive.toString.replace('y', 'z')); # addFive(3); # error: ‘x’ is undefined
at pointcut(callee(square)) before(x) { alert("x is ", x); }
at pointcut(callee(square)) before(x) { alert("x is ", x); }
square → envcode + advice ← squareAlias
(See OOPSLA'10 paper for more details)
Our example from before:
eval("XULBrowserWindow.setOverLink = " + XULBrowserWindow.setOverLink.toString().replace(/{/, "$& link = Fission.setOverLink(link);"));
Becomes
at pointcut(callee(XULBrowserWindow.setOverLink)) before(link) { link = Fission.setOverLink(link); }
More explicit, easier to read, more analyzable
(Do something, assuming {guarded resource1, guarded resource2, …})
Overlay
<modify selector="InputBindings" where="after"> <KeyBinding Modifiers="Ctrl" Key="L" Command="GoToLocation" /> </modify>
Becomes…
(Append <KeyBinding Modifiers="Ctrl" Key="L" Command="GoToLocation" /> to <Inputbindings>, {Require InputBindings, Last Key "Ctrl+L"})
We can treat the base document as an extension too:
(Define html#1, html#1 > head#2, html#1 > head#2 + body#3, html#1 > head#2 + body#3 > span#4, …, {Reject html#1, Reject html#1 > head#2, …})
Contributions