package textbender.o.rhinohide; // Copyright 2006-2007, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Textbender Software"), to deal in the Textbender Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Textbender Software, and to permit persons to whom the Textbender Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Textbender Software. THE TEXTBENDER SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE TEXTBENDER SOFTWARE OR THE USE OR OTHER DEALINGS IN THE TEXTBENDER SOFTWARE. import java.applet.Applet; import netscape.javascript.JSObject; import org.w3c.dom.Element; import org.w3c.dom.css.*; import textbender.g.hold.Hold; import textbender.g.lang.ThreadSafe; import textbender.o.rhinohide.core.*; import textbender.o.rhinohide.events.*; import textbender.o.rhinohide.ranges.RhiSelection; /** A global 'window' implemented as an overlay of a JavaScript global 'window'. * It represents the JavaScript runtime's global object. * * @see http://developer.mozilla.org/en/docs/DOM:window */ public @ThreadSafe final class RhiWindow extends RhiEventTarget implements ViewCSS { /** Constructs a RhiWindow. * Call {@linkplain #release() release}() when done with it; * e.g. when your applet is 'destroyed'. * * @param applet one of the applets of the document * * @return global window for that document */ public static RhiWindow createWindow( Applet applet ) { return new RhiWindow( JSObject.getWindow( applet )); } RhiWindow( JSObject jsObject ) { super( jsObject ); window = RhiWindow.this; if( getDocument().getImplementation().hasFeature( "Events", "2.0" )) { String script; JSObject jsoRelayFactory; script = relayFactoryScript( RelaySI.HANDLE_EVENT_SCRIPT ); // System.out.println( "RW script: \n" + script ); jsoRelayFactory = (JSObject)window.evalV( script ); relayFactorySI = new Rhinohide( RhiWindow.this, jsoRelayFactory ); script = relayFactoryScript( RelaySIP.HANDLE_EVENT_SCRIPT ); // System.out.println( "RW script: \n" + script ); jsoRelayFactory = (JSObject)window.evalV( script ); relayFactorySIP = new Rhinohide( RhiWindow.this, jsoRelayFactory ); } else // Exclude set-up for events, as work around to bug below (otherwise there would be no harm). { relayFactorySI = null; relayFactorySIP = null; } } // ------------------------------------------------------------------------------------ /** User-selected text (non-standard). */ public RhiSelection getSelection() { return RhiSelection.wrapSelection( window, (JSObject)call( "getSelection" )); } /** Factory to create event relays on the JavaScript side, for RelaySI. * [This is implementation, and will later be made private.] */ public Rhinohide relayFactorySI() { if( relayFactorySI == null ) throw new UnsupportedOperationException( "client does not support events" ); return relayFactorySI; } private final Rhinohide relayFactorySI; // Relays could be contructed in RelaySI itself, by eval() calls. These factories are slightly more efficient. Originally, they were an unsuccessful attempt to work around bug: http://reluk.ca/var/cache/textbender-javadoc/textbender/o/rhinohide/Rhinohide.html#stubborn-rhino /** Factory to create event relays on the JavaScript side, for RelaySIP. * [This is implementation, and will later be made private.] */ public Rhinohide relayFactorySIP() { if( relayFactorySIP == null ) throw new UnsupportedOperationException( "client does not support events" ); return relayFactorySIP; } private final Rhinohide relayFactorySIP; // - A b s t r a c t - V i e w -------------------------------------------------------- public RhiDocument getDocument() { return RhiDocument.wrapDocument( window, (JSObject)getMemberV( "document" )); } // - H o l d -------------------------------------------------------------------------- public void release() {} // - V i e w - C - S - S -------------------------------------------------------------- /** Not yet coded. * * @throws UnsupportedOperationException */ public CSSStyleDeclaration getComputedStyle( Element elt, String pseudoElt ) { throw new UnsupportedOperationException(); } // - W i n d o w ---------------------------------------------------------------------- public int getScreenX() { return ((Number)evalV( "if( 'screenX' in this ) screenX; else screenLeft;" )).intValue(); // screenLeft for IE and Opera } public int getScreenY() { return ((Number)evalV( "if( 'screenY' in this ) screenY; else screenTop;" )).intValue(); // screenTop for IE and Opera } //// P r i v a t e /////////////////////////////////////////////////////////////////////// /** Returns a script that evaluates (when executed) * to an event-relay factory. The factory is a JavaScript object * with a single function: createRelay(). A call to factory.createRelay() * returns a newly created relay. *

* Each relay constructed by the factory has... * [well, as this is now a private method, please see the code] *

*/ private static String relayFactoryScript( String handleEventScript ) { return "" // BUG, windows IE cannot parse the following, complains about unterminated string or something + " ( function() { \n" // anon. function literal, to avoid clobbering global namespace with var for new object + " this.createRelay = function() \n" + " { \n" + " var relay = new Object(); \n" + handleEventScript + " relay.addTo = function( target, type, useCapture ) \n" + " { \n" // + " target.addEventListener( type, relay.handleEvent, useCapture ); \n" + " target.addEventListener( type, this.handleEvent, useCapture ); \n" + " }; \n" + " relay.removeFrom = function( target, type, useCapture ) \n" + " { \n" // + " target.removeEventListener( type, relay.handleEvent, useCapture ); \n" + " target.removeEventListener( type, this.handleEvent, useCapture ); \n" + " }; \n" + " return relay; \n" + " }; \n" + " return this; \n" + " }).call( new Object() ); \n" // end function literal, and invoke on new object ; } }