/* AIRIntrospector.js - Revision: 1.5 */ /* ADOBE SYSTEMS INCORPORATED Copyright 2007-2008 Adobe Systems Incorporated. All Rights Reserved. NOTICE: Adobe permits you to modify and distribute this file only in accordance with the terms of Adobe AIR SDK license agreement. You may have received this file from a source other than Adobe. Nonetheless, you may modify or distribute this file only in accordance with such agreement. */ var air; (function(){ if(typeof air=='undefined') air = {}; air.Introspector = {}; // Check the runtime. if(typeof window.runtime!='undefined' && typeof window.nativeWindow!='undefined') var isAppSandbox = true; else var isAppSandbox = false; //======================================================================================================================================================= //Introspector.js //======================================================================================================================================================= //---------------------------------------------------------------------------------------------------- /** * @API air.Introspector.Console * @description Exposes log, warn, info, error, dump to the user * THIS IS THE ONLY SUPPORTED APIs */ air.Introspector.Console = { log: function(){ air.Introspector.logArguments(arguments, {htmlLoader:isAppSandbox?window.htmlLoader:null}); }, warn : function(){ air.Introspector.logArguments(arguments, {htmlLoader:isAppSandbox?window.htmlLoader:null, type:'warn'}); }, info : function(){ air.Introspector.logArguments(arguments, {htmlLoader:isAppSandbox?window.htmlLoader:null, type:'info'}); }, error : function(){ air.Introspector.logArguments(arguments, {htmlLoader:isAppSandbox?window.htmlLoader:null, type:'error'}); }, dump : function(obj, level){ air.Introspector.logArguments(air.Introspector.dump(obj, level), {htmlLoader: isAppSandbox?window.htmlLoader:null, usePre:true}); } }; //---------------------------------------------------------------------------------------------------- air.Introspector.config = { showTimestamp: true, //Make the console show time stamps before each line showSender: true, //Make the console show time stamps wrapColumns: 2000, //Source files are soft-wrapped at around 2000 columns by default flashTabLabels: true, //Console and xhr columns can flash whenever something happend to them (eg. logged something). You can turn it off //by setting this to false closeIntrospectorOnExit: true, //Makes the inspector window close when the last window closed debugRuntimeObjects: true, //Also expand ActionScript objects introspectorKey:122, //Inspect key - by default it is F11 (122) debuggerKey:123, //Toggle inspectors visibility - by default it is F12 (123) useAirDebugHtml: false, //Internal only }; /** * @module air.Introspector */ air.Introspector.extend = function(dst, src){ //Take every property from src and put it in dst for(var i in src){ dst[i]=src[i]; } }; // Checking if the user has configured Introspector using global AIRIntrospectorConfig variable if(typeof AIRIntrospectorConfig!='undefined'){ air.Introspector.extend(air.Introspector.config, AIRIntrospectorConfig); } var eventListeners = []; // Can not expand ActionScript objects from remote sandbox - we can not even access ActionScript from there // just disabled this feature if(!isAppSandbox) air.Introspector.config.debugRuntimeObjects = false; // Made this use g/setters in order to make it easy to send its value over the bridge air.Introspector.__defineGetter__('inspect', function(){ return air.Introspector._inspect; }); air.Introspector.__defineSetter__('inspect', function(value){ air.Introspector._inspect=value; if(!isAppSandbox){ setTimeout(function(){ air.Introspector.noBridge(function(){ parentSandboxBridge.air_Introspector_setInspect(value); }); }, 0); }else{ if(!value){ try{ air.Introspector.hideHighlight(); }catch(e){} } } }); air.Introspector.extend(air.Introspector, { /** * Makes it easier to acces runtime packages * it makes sense only in the application sandbox */ runtime: isAppSandbox?{ HTMLLoader : window.runtime.flash.html.HTMLLoader, Event : window.runtime.flash.events.Event, IOErrorEvent: window.runtime.flash.events.IOErrorEvent, NativeApplication: window.runtime.flash.desktop.NativeApplication, URLLoader : window.runtime.flash.net.URLLoader, URLRequest : window.runtime.flash.net.URLRequest, NativeWindowInitOptions : window.runtime.flash.display.NativeWindowInitOptions, Capabilities: window.runtime.flash.system.Capabilities, trace : window.runtime.trace, }:null, _inspect: false, remoteInspect: false, canClick: false, bridgeCallbacks: [], /** * Different coloring styles for tag names, by default 'default' is used * Undocumented feature * - you can change the color of elements while inspecting by tag name, check bellow the body: 0x00CC00 line, * uncomment that line, duplicate and change it with your own colors */ highlightBgColors: { 'default': 0xFFCC00, //body: 0x00CC00, }, /** * @function trimRegExp * @description Trims spaces from a string * @private */ trimRegExp: /^[\s\r\n]*([\s\S]*?)[\s\r\n]*$/g, trim:function(str){ return str.replace(air.Introspector.trimRegExp, '$1'); }, /** * @function blockWrap * @description Wraps a string by air.Introspector.config.wrapColumns columns */ blockWrap: function(str){ //used for spliting large lines in
var cols = air.Introspector.config.wrapColumns; var lines = str.split(/\n/); var buffer = []; var l = lines.length; var lineNumbers = []; for(var i=0;icols){ buffer.push(line.substr(0, cols)); line = line.substr(cols); lineNumbers.push(''); } buffer.push(line); } lineNumbers.push('EOF'); return [buffer.join('\n'), lineNumbers.join('\n')]; }, /** * @function getTextFormat * @description Returns a new flash TextField */ createTextField: function(parentSprite, fontSize, fontBold) { if(isAppSandbox){ var tf = new runtime.flash.text.TextField(); tf.embedFonts = false; tf.autoSize = runtime.flash.text.TextFieldAutoSize.LEFT; tf.antiAliasType = runtime.flash.text.AntiAliasType.ADVANCED; tf.defaultTextFormat = air.Introspector.getTextFormat(fontSize, fontBold); tf.selectable = false; tf.mouseEnabled = true; tf.x = 4; tf.text = ""; if(parentSprite.numChildren > 0) { var sibling = parentSprite.getChildAt(parentSprite.numChildren - 1); tf.y = sibling.y + sibling.height + 15; } parentSprite.addChild(tf); return tf; }else{ //should not get here return null; } }, /** * @function getTextFormat * Returns a new flash TextFormat * see createTextField */ getTextFormat: function(fontSize, fontBold){ if(isAppSandbox){ var format = new runtime.flash.text.TextFormat(); format.size = fontSize; format.font = "Tahoma"; format.bold = fontBold; format.color = 0x330066; return format; }else{ //should not get here return null; } }, /** * @function extendRect * @description Initializes the sprite with values from the rectangle */ extendRect: function(sprite, rect){ sprite.x = rect.x; sprite.y = rect.y; sprite.width = rect.width; sprite.height = rect.height; sprite.scaleX = rect.scaleX; sprite.scaleY = rect.scaleY; }, /** * @function showHighlight * @description Shows a highlighting flash sprite using coordinates from rectangle */ showHighlight: function(rect){ if(isAppSandbox){ //dehilight everyone else var ownedWindows = air.Introspector.getHtmlWindows(); for(var i=ownedWindows.length-1;i>=0;i--){ try{ ownedWindows[i].htmlLoader.window.air.Introspector.hideHighlight(); }catch(e){ //no air.Introspector } } air.Introspector.extendRect(air.Introspector.highlightSprite, rect); }else{ setTimeout(function(){ air.Introspector.noBridge(function(){ parentSandboxBridge.air_Introspector_showHighlight(rect); }); }, 0); } }, /** * @function hideHighlight * @description Make the higlight box go away */ hideHighlight: function(){ if(isAppSandbox){ air.Introspector.extendRect(air.Introspector.highlightSprite, {x:0, y:0, width:0, height:0, scaleX:0, scaleY:0}); air.Introspector.highlightText.visible = false; }else{ setTimeout(function(){ try{ parentSandboxBridge.air_Introspector_hideHighlight(); }catch(e){ // no bridge yet } }, 0); } }, /** * @function remoteClick * @description Make the remote sandbox know that the inspection finished */ remoteClick: function(){ air.Introspector.debugWindow.finishInspect(false); air.Introspector.hideHighlight(); }, /** * @function createHighlight * @description Creates a flash sprite used to higlight elements * By using this method we are sure that no dom manipulation is done and * no style is changed in HTML. */ createHighlight: function(){ if(isAppSandbox){ var sprite = new runtime.flash.display.Sprite(); sprite.mouseEnabled = false; sprite.width = 0; sprite.height = 0; sprite.buttonMode = true; var prevent = function(element, event, isClick){ air.Introspector.addEventListener(element, event, function(e){ if((air.Introspector.inspect||air.Introspector.remoteInspect) &&sprite.hitTestPoint(e.stageX, e.stageY)){ e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); if(isClick&&air.Introspector.canClick){ if(air.Introspector.remoteInspect){ try{ air.Introspector.inspectFrame.contentWindow.childSandboxBridge.air_Introspector_remoteClick(); }catch(e){ air.Introspector.noChildBridge(air.Introspector.inspectFrame); } }else{ air.Introspector.debugWindow.finishInspect(false); air.Introspector.hideHighlight(); } } } }, true, 2000000); }; var check = function(element, event){ air.Introspector.addEventListener(element, event, function(e){ if((air.Introspector.inspect||air.Introspector.remoteInspect)&&nativeWindow.active){ setTimeout(function(){ air.Introspector.canClick = true; }, 100); } }, true, 200000); } var labelMover = function(element, event){ air.Introspector.addEventListener(element, event, function(e){ if((air.Introspector.inspect||air.Introspector.remoteInspect)){ air.Introspector.highlightText.x = e.stageX+15; air.Introspector.highlightText.y = e.stageY+15; // air.Introspector.highlightText.visible = true; }else{ air.Introspector.highlightText.visible = false; } }, true, 200000); } prevent(htmlLoader.stage, runtime.flash.events.MouseEvent.CLICK, true); prevent(htmlLoader.stage, runtime.flash.events.MouseEvent.MOUSE_DOWN); prevent(htmlLoader.stage, runtime.flash.events.MouseEvent.MOUSE_UP); prevent(htmlLoader.stage, runtime.flash.events.MouseEvent.DOUBLE_CLICK); check(htmlLoader.stage, runtime.flash.events.MouseEvent.MOUSE_MOVE); check(nativeWindow, runtime.flash.events.Event.ACTIVATE); labelMover(htmlLoader.stage, runtime.flash.events.MouseEvent.MOUSE_MOVE); window.htmlLoader.stage.addChild(sprite); air.Introspector.highlightSprite = sprite; air.Introspector.highlightText = new runtime.flash.display.Sprite(); window.htmlLoader.stage.addChild(air.Introspector.highlightText); air.Introspector.highlightText.graphics.beginFill(0xeeeeee, 0.8); air.Introspector.highlightText.graphics.lineStyle(1, 0xeeeeee, 0.9, false); air.Introspector.highlightText.graphics.drawRect(0, 0, 250, 40); air.Introspector.highlightText.visible = false; air.Introspector.highlightLine1 = air.Introspector.createTextField(air.Introspector.highlightText, 16, true); air.Introspector.highlightLine2 = air.Introspector.createTextField(air.Introspector.highlightText, 10, false); }else{ //should not be here } }, /** * @function addEventListener * @description Add a listener and stores it for future cleanup */ addEventListener: function(obj, eventName, listener, capture, priority){ eventListeners.push([obj, eventName, listener, capture]); obj.addEventListener(eventName, listener, capture, priority); }, /** * @function removeEventListener * @description Removes listener */ removeEventListener: function(obj, eventName, listener, capture){ for(var i=eventListeners.length-1;i>=0;i--){ var l = eventListeners[i]; if(l[0]==obj && l[1]==eventName && l[2]==listener && l[3]==capture) { eventListeners.splice(i, 1); break; } } obj.removeEventListener(eventName, listener, capture); }, /** * @function drawRect * @description Draw a rectangle using ActionScript, also use tagName to find out which color to use * @see air.Introspector.highlightBgColors */ drawRect: function (rect, tagName){ var htmlLoaderBounds = htmlLoader.getBounds(htmlLoader.stage); rect.x += htmlLoaderBounds.x; rect.y += htmlLoaderBounds.y; rect.scaleX = 1; rect.scaleY = 1; air.Introspector.showHighlight(rect); air.Introspector.highlightSprite.graphics.clear(); var bgColor = air.Introspector.highlightBgColors[tagName.toLowerCase()]; if(typeof bgColor=='undefined') bgColor = air.Introspector.highlightBgColors['default']; air.Introspector.highlightSprite.graphics.beginFill(bgColor, 0.2); air.Introspector.highlightSprite.graphics.lineStyle(3, bgColor, 0.9, false); air.Introspector.highlightSprite.graphics.drawRect(0, 0, rect.width, rect.height); }, /** * @function highlightElement * @description Highlight element e. Get its bounding box and send it directly or over the bridge to air.Introspector.drawRect * @also air.Introspector.drawRect */ highlightElement: function(e, callback){ var rect = air.Introspector.getBorderBox(e); if(rect==false) return; if(isAppSandbox){ air.Introspector.drawRect(rect, e.tagName); }else{ setTimeout(function(){ try{ if(!isNaN(rect.width)&&!isNaN(rect.x)){ air.Introspector.noBridge(function(){ parentSandboxBridge.air_Introspector_drawRect(rect, e.tagName); }); } }catch(e){ } if(typeof callback!='undefined') callback(); }, 0); } }, /** * @function addKeyboardEvents * @description Registers events on every window that includes AIRDebug.js. * * By default F11 enables the inspect tool * F12 pops up the debug tool */ addKeyboardEvents: function(sprite){ air.Introspector.addEventListener(sprite, runtime.flash.events.KeyboardEvent.KEY_DOWN, function(e){ if(e.keyCode==air.Introspector.config.introspectorKey){ //F11 key pressed if(typeof air.Introspector.lastElement!='undefined'&&(air.Introspector.lastElement.nodeName=='IFRAME'||air.Introspector.lastElement.nodeName=='FRAME')){ try{ var contentWindow = air.Introspector.lastElement.contentWindow; if(typeof contentWindow.childSandboxBridge!='undefined'&& typeof contentWindow.childSandboxBridge.air_Introspector_isDebugOpen!='undefined'&& typeof contentWindow.childSandboxBridge.air_Introspector_toggleInspect!='undefined') { if(contentWindow.childSandboxBridge.air_Introspector_isDebugOpen()){ contentWindow.childSandboxBridge.air_Introspector_toggleInspect(); e.preventDefault(); e.stopPropagation(); return; } } }catch(e){ //it looks like no debugger in that iframe. go ahead with app sandbox debugger } } air.Introspector.init(false, true, function(){ air.Introspector.debugWindow.toggleInspect(); }); e.preventDefault(); e.stopPropagation(); }else if(e.keyCode==air.Introspector.config.debuggerKey){ //F12 key pressed air.Introspector.toggleWindow(); e.preventDefault(); e.stopPropagation(); }else if(e.keyCode==27&&air.Introspector.inspect){ air.Introspector.debugWindow.finishInspect(); air.Introspector.hideHighlight(); e.preventDefault(); e.stopPropagation(); }else if(e.ctrlKey==true&&e.altKey==false){ var tab = null; switch(e.keyCode){ case runtime.flash.ui.Keyboard.NUMBER_1: tab = 0; break; case runtime.flash.ui.Keyboard.NUMBER_2: tab = 1; break; case runtime.flash.ui.Keyboard.NUMBER_3: tab = 2; break; case runtime.flash.ui.Keyboard.NUMBER_4: tab = 3; break; case runtime.flash.ui.Keyboard.NUMBER_5: tab = 4; break; case runtime.flash.ui.Keyboard.NUMBER_6: tab = 5; break; } if(tab!=null){ air.Introspector.init(false, true, function(){ air.Introspector.debugWindow.setTab(tab); }); e.preventDefault(); e.stopPropagation(); } } }, true, 1000000); }, /** * @function showHighlightLabels * @description Make the tooltip labels near the highlighting box appear and tell the id/tag name/outer HTML */ showHighlightLabels: function(id, nodeName, outerHTML){ if(typeof id!='undefined'&&id.length!=0){ air.Introspector.highlightLine1.text = nodeName+' - '+id; }else{ air.Introspector.highlightLine1.text = nodeName; } if(air.Introspector.canClick){ air.Introspector.highlightLine2.text = outerHTML.substr(0, 40).replace(/\n/g, '\\n')+'...'; }else{ air.Introspector.highlightLine2.text = 'Click to activate window'; window.clearTimeout(air.Introspector.clickToActivateTimeout); air.Introspector.clickToActivateTimeout = setTimeout(function(){ air.Introspector.highlightLine2.text = outerHTML.substr(0, 40).replace(/\n/g, '\\n')+'...'; }, 400) } air.Introspector.highlightText.visible = true; }, /** * @function registerUncaughtExceptionListener * @description Catches all uncaught exceptions from javascript and shows them in the console */ registerUncaughtExceptionListener: function(){ air.Introspector.addEventListener(window.htmlLoader, runtime.flash.events.HTMLUncaughtScriptExceptionEvent.UNCAUGHT_SCRIPT_EXCEPTION , function(e){ if(e.exceptionValue && e.exceptionValue.air_Introspector_setParentSandboxBridge == true && e.exceptionValue.air_Introspector_version == air.Introspector.version) { air.Introspector.registerFramesParentSandboxBridge(); e.preventDefault(); return; } air.Introspector.logError(e.exceptionValue, {htmlLoader:window.htmlLoader}); // e.preventDefault(); }); }, /** * @function registerCloseEventListener * @description */ registerCloseEventListener: function(){ air.Introspector.addEventListener(window.nativeWindow, air.Introspector.runtime.Event.CLOSE, function(){ var debugWindow = air.Introspector.findDebugWindow(); if(debugWindow!=null){ debugWindow.closedWindow(window.htmlLoader); } }); }, /** * @function registerCompleteEventLisener * @description Make the Introspector window knwo that we are complete. Register parentSandboxBridge on every frame */ registerCompleteEventListener: function(){ air.Introspector.addEventListener(window.htmlLoader, air.Introspector.runtime.Event.COMPLETE, function(){ air.Introspector.removeEventListener(window.htmlLoader, air.Introspector.runtime.Event.COMPLETE, arguments.callee); try{ //announce the debugWindow to refresh DOM and assets var debugWindow = air.Introspector.findDebugWindow(); if(debugWindow!=null){ if(debugWindow.isLoaded){ debugWindow.completeWindow(window.htmlLoader); } } air.Introspector.registerFramesParentSandboxBridge(); }catch(e){ runtime.trace(e); runtime.trace(e.line); air.Introspector.Console.log(e); } }); }, /** * @function registerFramesParentSandboxBridge * @description All frames should know about us - registering parentSandboxBridge */ registerFramesParentSandboxBridge: function(){ //var modified = false; var iframes = document.getElementsByTagName('iframe'); for(var i=iframes.length-1;i>=0;i--){ air.Introspector.registerFrame(iframes[i]); } var frames = document.getElementsByTagName('frame'); for(var i=frames.length-1;i>=0;i--){ air.Introspector.registerFrame(frames[i]); } //return modified; }, /** * @function registerDeactivateEventLisener * @description Hides the highlighting rectangle and deactivates inspect-clicking for this window */ registerDeactivateEventListener: function(){ air.Introspector.addEventListener(window.nativeWindow, air.Introspector.runtime.Event.DEACTIVATE, function(){ air.Introspector.hideHighlight(); air.Introspector.canClick =false; }); }, /** * @function registerChildSandboxBridge * @description Register childSandboxBridge for current iframe */ registerChildSandboxBridge: function(){ if(typeof childSandboxBridge=='undefined') childSandboxBridge={}; try{ childSandboxBridge.air_Introspector_remoteClick = function (){ try{ air.Introspector.remoteClick(); }catch(e){ alert(e+' '+e.line); } } childSandboxBridge.air_Introspector_isDebugOpen = function(){ return typeof air.Introspector.debugWindow!='undefined'; } childSandboxBridge.air_Introspector_toggleInspect = function (){ air.Introspector.init(false, true, function() { air.Introspector.debugWindow.toggleInspect(); }); } childSandboxBridge.air_Introspector_bridgeLoaded = function(){ var l = air.Introspector.bridgeCallbacks; for(var i=0;i =0;i--){ var l = eventListeners[i]; try{ l[0].removeEventListener(l[1], l[2], l[3]); }catch(e){} } eventListeners = []; try{ window.htmlLoader.stage.removeChild(air.Introspector.highlightText); }catch(e){} }, /** * @function register * @description Registers current window in debugger * * Captures every XHR object created and any uncaught exception * and sends it to the debugger */ register: function(){ if (window.XMLHttpRequest && window.XMLHttpRequest.prototype){ window.XMLHttpRequest.prototype.debugopen = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.debugsend = window.XMLHttpRequest.prototype.send; window.XMLHttpRequest.prototype.open = function(method, url, asyncFlag, username, password){ if(typeof this.doNotDebug=='undefined'){ var debugWindow = air.Introspector.findDebugWindow(); if(debugWindow!=null){ debugWindow.logNet(this, method, url, asyncFlag); } } return this.debugopen(method, url, asyncFlag, username, password); }; window.XMLHttpRequest.prototype.send = function(obj){ if(typeof this.doNotDebug=='undefined'){ var self = this; var debugWindow = air.Introspector.findDebugWindow(); if(debugWindow!=null){ var a = this.onreadystatechange; this.onreadystatechange = function(){ if (typeof a == 'function')a.call(self); debugWindow.logNet(self, 'unknown', '', false); }; if(typeof self.doNotDebug=='undefined') debugWindow.logNetSend(this, obj); } var ret = this.debugsend(obj); if(debugWindow!=null){ debugWindow.logNetSend(this, obj); } return ret; }else{ return this.debugsend(obj); } } } if(isAppSandbox){ air.Introspector.addKeyboardEvents(window.htmlLoader); air.Introspector.registerUncaughtExceptionListener(); air.Introspector.registerCloseEventListener(); air.Introspector.registerCompleteEventListener(); air.Introspector.registerDeactivateEventListener(); air.Introspector.createHighlight(); }else{ air.Introspector.registerChildSandboxBridge(); } air.Introspector.waitForBody(document, function(){ try{ if(!isAppSandbox){ air.Introspector.createOpenConsoleButton(); } air.Introspector.registerDOMEventListeners(); window.addEventListener('unload', function(){ try{ air.Introspector.cleanup(); if(!isAppSandbox){ //our debugger can NOT live without it's parent air.Introspector.debugWindow.window.close(); } }catch(e){ } }); }catch(e){ if(isAppSandbox){ runtime.trace(e); runtime.trace(e.line); } air.Introspector.Console.log(e); } }); }, /** * @function registerFrame * @description Makes the parentSandboxBridge available to frame */ registerFrame: function(frame){ if(typeof frame.contentWindow.parentSandboxBridge=='undefined') frame.contentWindow.parentSandboxBridge = {}; /*frame.contentWindow.parentSandboxBridge.trace = function(a){ runtime.trace(a); };*/ //checking that the bridge is not already there /*var modified = typeof frame.contentWindow.parentSandboxBridge.air_Introspector_hideHighlight=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_showHighlight=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_drawRect=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_setInspect=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_getWindowTitle=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_checkNativeWindow=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_writeConsoleToClipboard=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_writeConsoleToFile=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_writeConfigFile=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_readConfigFile=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_showHighlightLabels=='undefined' || typeof frame.contentWindow.parentSandboxBridge.air_Introspector_getFrameId=='undefined';*/ frame.contentWindow.parentSandboxBridge.air_Introspector_hideHighlight = function(){ air.Introspector.hideHighlight(); }; frame.contentWindow.parentSandboxBridge.air_Introspector_showHighlight = function(rect){ air.Introspector.showHighlight(rect); }; frame.contentWindow.parentSandboxBridge.air_Introspector_drawRect = function(rect, tagName){ var frameRect = air.Introspector.getBorderBox(frame); var blw = air.Introspector.getIntProp(frame, "border-left-width"); var btw = air.Introspector.getIntProp(frame, "border-top-width"); if(frameRect==null) return; rect.x+=frameRect.x+2*blw; rect.y+=frameRect.y+2*btw; air.Introspector.drawRect(rect, tagName); }; frame.contentWindow.parentSandboxBridge.air_Introspector_setInspect = function(enabled){ air.Introspector.inspectFrame = enabled?frame:null; air.Introspector.remoteInspect = enabled; if(!enabled){ air.Introspector.hideHighlight(); } }; frame.contentWindow.parentSandboxBridge.air_Introspector_getWindowTitle = function(){ return document.title; }; frame.contentWindow.parentSandboxBridge.air_Introspector_checkNativeWindow = function(title){ var htmlWindows = air.Introspector.runtime.NativeApplication.nativeApplication.openedWindows; for(var i=htmlWindows.length-1;i>=0;i--){ if(htmlWindows[i].title==title){ return true; } } return false; }; frame.contentWindow.parentSandboxBridge.air_Introspector_writeConsoleToClipboard = function(str){ air.Introspector.writeConsoleToClipboard(str); }; frame.contentWindow.parentSandboxBridge.air_Introspector_writeConsoleToFile = function(str){ air.Introspector.writeConsoleToFile(str); }; frame.contentWindow.parentSandboxBridge.air_Introspector_writeConfigFile = function(config){ return air.Introspector.writeConfigFile(config, true); } frame.contentWindow.parentSandboxBridge.air_Introspector_readConfigFile = function(){ return air.Introspector.readConfigFile(true); } frame.contentWindow.parentSandboxBridge.air_Introspector_showHighlightLabels = function(id, nodeName, outerHTML){ air.Introspector.showHighlightLabels(id, nodeName, outerHTML); }; frame.contentWindow.parentSandboxBridge.air_Introspector_getFrameId = function(){ return frame.id; } frame.contentWindow.parentSandboxBridge.air_Introspector_getNextWindowId = function(){ return ++air.Introspector.times; } if(typeof frame.contentWindow.childSandboxBridge!='undefined' && typeof frame.contentWindow.childSandboxBridge.air_Introspector_bridgeLoaded!='undefined'){ frame.contentWindow.childSandboxBridge.air_Introspector_bridgeLoaded(); } //return modified; }, /** * @function waitForBody * @description Wait until document.body is available */ waitForBody: function(document, callback){ if(document.body){ callback(); }else{ setTimeout(air.Introspector.waitForBody, 10, document, callback); } }, /** * @function toggleWindow * @description Shows/Hides the debug tool */ toggleWindow:function(){ air.Introspector.init(true, false, function(justCreated){ if(!justCreated) air.Introspector.debugWindow.nativeWindow.visible ^= true; }); }, /** * @function init * @description Makes sure the debug tool is enabled */ init: function(showLoader, toggle, callback){ if(!air.Introspector.canInit()) return; if(typeof showLoader=='undefined') showLoader = false; if(typeof toggle=='undefined') toggle = true; if(isAppSandbox){ if(typeof air.Introspector.debugWindow=='undefined' || air.Introspector.debugWindow.nativeWindow.closed){ delete air.Introspector.debugWindow; var debugWindow = air.Introspector.findDebugWindow(); if(debugWindow!=null && !debugWindow.nativeWindow.closed){ air.Introspector.debugWindow = debugWindow; if(toggle){ air.Introspector.debugWindow.nativeWindow.visible = true; if(!showLoader){ nativeWindow.activate(); } } callback(false); }else{ air.Introspector.loadDebugger(function(debugWindow){ air.Introspector.debugWindow = debugWindow; callback(true); }, showLoader); } }else{ if(toggle){ if(showLoader){ air.Introspector.debugWindow.nativeWindow.activate(); } } callback(false); } }else{ if(typeof activeWindow=='undefined'){ air.Introspector.registerChildSandboxBridge(); } if(typeof air.Introspector.debugWindow=='undefined'|| typeof air.Introspector.debugWindow.window.air=='undefined'){ /* (air.Introspector.debugWindow.isWindowCreated &&air.Introspector.debugWindow.isLoaded &&air.Introspector.debugWindow.window &&!parentSandboxBridge.air_Introspector_checkNativeWindow(air.Introspector.parentWindowTitle + ': '+air.Introspector.debugWindow.window.document.title))){*/ delete air.Introspector.debugWindow; air.Introspector.loadDebugger(function(debugWindow){ air.Introspector.debugWindow = debugWindow; callback(true); }); // air.Introspector.debugWindow = new air.Introspector.DebugWindow ({activateDebug: showLoader, activeWindow: window}); }else if(!air.Introspector.debugWindow.isWindowCreated){ return; }else{ callback(false); } } }, times:0, //make the window.open page name unique - this is the number of opened and closed introspector windows /** * @function tryCreateWindow * @description window.Open in browser/remote sandbox is not allowed if the action is not iniated by the user (eg. user gesture, mouse click) * We can only wait for that moment. Until that happends we record all the callbacks and run them when the Introspector is laoded * @runs in remote sandbox only */ tryCreateWindow: function(callbacks){ // try{ var self = this; var w; var iframeId; /* if(typeof parentSandboxBridge=='undefined'){ air.Introspector.noBridge(function(){ air.Introspector.tryCreateWindow(callbacks); }); return; }*/ air.Introspector.parentWindowTitle = parentSandboxBridge.air_Introspector_getWindowTitle(); if(typeof parentSandboxBridge!='undefined'&&typeof parentSandboxBridge.air_Introspector_getFrameId!='undefined') iframeId = parentSandboxBridge.air_Introspector_getFrameId(); if(typeof parentSandboxBridge!='undefined'&&typeof parentSandboxBridge.air_Introspector_getNextWindowId!='undefined') air.Introspector.times = parentSandboxBridge.air_Introspector_getNextWindowId(); else air.Introspector.times ++ ; //we should never be here - just in case, we should increment this if(typeof air.Introspector.config.useAirDebugHtml=='undefined'||air.Introspector.config.useAirDebugHtml==false){ w = window.open('about:blank', 'debugger'+air.Introspector.times, 'width=640,height=480,resizable=1'); if(w&&w.document){ w.isAppSandbox = isAppSandbox; w.opener = window; w.iframeId = iframeId; w.initCallbacks = callbacks; w.activeWindow = window; w.isLoaded = false; w.config = air.Introspector.config; w.document.open(); w.document.write(air.Introspector.contentString); w.document.close(); } }else{ w = window.open('DebugUI.html', 'debugger'+air.Introspector.times, 'width=640,height=480,resizable=1'); if(w&&w.document){ w.opener = window; w.iframeId = iframeId; w.activeWindow = window; w.config = air.Introspector.config; w.initCallbacks = callbacks; w.isLoaded = false; w.isAppSandbox = isAppSandbox; } } return w; // }catch(e){ // alert(e+' '+e.line); // } }, /** * @function loadDebugger * @description Loads the debugger window, register callbacks until it is ready * @runs in application sandbox only */ loadDebugger: function(callback, activateDebug){ var htmlLoader; var loadDebugger = arguments.callee; if(loadDebugger.htmlLoader && typeof loadDebugger.htmlLoader.window.isLoaded != 'undefined'){ if(loadDebugger.htmlLoader.window.isLoaded){ callback(loadDebugger.htmlLoader.window.debugWindow); }else{ if(loadDebugger.htmlLoader.window.initCallbacks){ loadDebugger.htmlLoader.window.initCallbacks.push(callback); }else{ loadDebugger.initCallbacks.push(callback); } } return; } if(typeof loadDebugger.initCallbacks=='undefined'){ loadDebugger.initCallbacks = [function(){ delete loadDebugger.initCallbacks; }, callback]; }else{ loadDebugger.initCallbacks.push(callback); } if(isAppSandbox){ htmlLoader = air.Introspector.runtime.HTMLLoader.createRootWindow(false); air.Introspector.addEventListener(htmlLoader, air.Introspector.runtime.Event.HTML_DOM_INITIALIZE, function(){ try{ air.Introspector.removeEventListener(htmlLoader, air.Introspector.runtime.Event.HTML_DOM_INITIALIZE, arguments.callee); htmlLoader.window.initCallbacks = loadDebugger.initCallbacks; htmlLoader.window.isLoaded = false; htmlLoader.window.config = air.Introspector.config; htmlLoader.window.activateDebug = activateDebug; htmlLoader.window.isAppSandbox = isAppSandbox; }catch(e){ air.Introspector.runtime.trace(e); air.Introspector.runtime.trace(e.line); } }); htmlLoader.window.isLoaded = false; var nativeWindow = htmlLoader.stage.nativeWindow; nativeWindow.width = 640; nativeWindow.height = 480; air.Introspector.addEventListener(htmlLoader, runtime.flash.events.HTMLUncaughtScriptExceptionEvent.UNCAUGHT_SCRIPT_EXCEPTION, function(e){ air.Introspector.logError(e.exceptionValue, {htmlLoader: self.htmlLoader}); e.preventDefault(); }); if(typeof air.Introspector.config.useAirDebugHtml=='undefined'||air.Introspector.config.useAirDebugHtml==false){ if(typeof htmlLoader.placeLoadStringContentInApplicationSandbox!='undefined'){ //since AIR1.5 the htmlLoader will not allow string load in app sandbox htmlLoader.placeLoadStringContentInApplicationSandbox= true; } htmlLoader.loadString(air.Introspector.contentString); if(typeof htmlLoader.placeLoadStringContentInApplicationSandbox!='undefined'){ //switch it back to false after load is complete htmlLoader.placeLoadStringContentInApplicationSandbox= false; } }else{ htmlLoader.load(new air.Introspector.runtime.URLRequest('app:/DebugUI.html')); } }else{ air.Introspector.noBridge(function(){ var w = air.Introspector.tryCreateWindow(loadDebugger.initCallbacks); if(w){ var htmlLoader = {window: w}; loadDebugger.htmlLoader = htmlLoader; } }); } loadDebugger.htmlLoader = htmlLoader; }, /** * @function findDebugWindow * @description Look up the Introspector in other windows. Maybe somebody else just opened it before us. */ findDebugWindow: function(){ if(isAppSandbox){ try{ if(air.Introspector.debugWindow&&air.Introspector.debugWindow.nativeWindow.closed==false) return air.Introspector.debugWindow; }catch(e){ } try{ var htmlWindows = air.Introspector.getHtmlWindows(true); for(var i=htmlWindows.length-1;i>=0;i--){ try{ if(typeof htmlWindows[i].htmlLoader.window.air!='undefined' && typeof htmlWindows[i].htmlLoader.window.air.Introspector!='undefined' && typeof htmlWindows[i].htmlLoader.window.air.Introspector.debugWindow!='undefined' && htmlWindows[i].htmlLoader.window.air.Introspector.debugWindow.nativeWindow.closed==false && htmlWindows[i].htmlLoader.window.isAppSandbox ) { return htmlWindows[i].htmlLoader.window.air.Introspector.debugWindow; } }catch(e){ //this window is not initialized yet //just get next window } } }catch(e){} }else{ return air.Introspector.debugWindow; } return null; }, //application browser formats // 0 - text // 1 - images // 2 - xml (you may want to add your own xml type here) formats : { 'png':1, 'gif':1, 'zip':1, 'air':1, 'jpg':1, 'jpeg':1, 'txt':0, 'html':0, 'js':0, 'xml':2, 'opml':2, 'css':0, 'htm':0, '':0 }, /** * @function canInit * @description Check if we got parentSandboxBridge available * @disabled */ canInit: function(){ /* if(!isAppSandbox&&typeof parentSandboxBridge=='undefined'){ alert('You need to include AIRIntrospector.js in application sandbox too!'); return false; }*/ return true; }, /** * @function logArguments * @description */ logArguments: function(args, config){ if(!air.Introspector.canInit()) return; config.timestamp = new Date(); air.Introspector.init(config.type=='error', true, function(){ air.Introspector.debugWindow.logArguments(args, config); }); }, /** * @function logError * @description */ logError: function(error, config){ air.Introspector.init(false, true, function(){ air.Introspector.debugWindow.logError(error, config); }); }, /** * @function showCssElement * @description */ showCssElement: function(element){ var debugWindow = air.Introspector.findDebugWindow(); if(debugWindow){ debugWindow.showCssElement(element); } }, checkIfIsInstanceOfHTMLLoader: function (child){ var className = runtime.flash.utils.getQualifiedClassName(child); if( className == "flash.html::HTMLLoader" ) return true; if( className == "mx.core::FlexHTMLLoader" ) return true; return false; }, /** * @function findLoader * @description Finds the first HTMLLoader in flash display object list */ findLoader: function (stage, loaders){ try{ for(var i=stage.numChildren-1;i>=0;i--){ var child = stage.getChildAt(i); if(air.Introspector.checkIfIsInstanceOfHTMLLoader(child)){ loaders.push([child]); }else if(child.htmlLoader!=null&&air.Introspector.checkIfIsInstanceOfHTMLLoader(child.htmlLoader)){ loaders.push([child.htmlLoader, child.id || child.toString()]); }else{ air.Introspector.findLoader(child, loaders); } } }catch(e){ } return null; }, /** * @function getHtmlWindows * @description Returns an array of all HTML windows */ getHtmlWindows: function(includeInspectors){ if(isAppSandbox){ var windowNodes = []; var windows = air.Introspector.runtime.NativeApplication.nativeApplication.openedWindows; for(var i=windows.length-1;i>=0;i--){ var loaders = []; air.Introspector.findLoader(windows[i].stage, loaders); for(var j=loaders.length-1;j>=0;j--){ var loaderItem = loaders[j]; var loader = loaderItem[0]; var label = loaderItem[1]; if(typeof includeInspectors=='undefined' && typeof loader.window!='undefined' && typeof loader.window.air!='undefined' && typeof loader.window.air.Introspector!='undefined' && typeof loader.window.air.Introspector.localIframeDebug != 'undefined' ){ continue; } windowNodes.push({ nativeWindow: windows[i], stage: windows[i].stage, htmlLoader : loader, label: label }); } } return windowNodes; }else{ //should not be here return []; } }, /** * @function twoDigits * @description int 2 string with two digits */ twoDigits: function(val){ if(val<10) return '0'+val; return val+''; }, /** * @function escapeHtml * @description Escapes html in order to display it in html */ escapeHtml: function(html){ return (html+'').replace(/&/g, '&').replace(/"/g, """).replace(//g, '>'); }, tree: { }, /** * @function isNumberObject * @description */ isNumberObject: function(obj){ try{ //can we catch isNaN only for NaN return (obj+0==obj&&!isNaN(obj)); }catch(e){ } return false; }, /** * @function isStringObject * @description */ isStringObject: function(obj){ try{ return (typeof(obj.match) != "undefined" && obj.match.toString().indexOf("[native code]")>0); }catch(e){ } return false; }, /** * @function isDateObject * @description */ isDateObject: function(obj){ try{ return (typeof(obj.getDate) != "undefined" && obj.getDate.toString().indexOf("[native code]")>0); }catch(e){ } return false; }, /** * @function isArgumentsObject * @description */ isArgumentsObject: function(obj){ try{ return obj.toString()=='[object Arguments]'; }catch(e){ } return false; }, /** * @function isXMLObject * @description */ isXMLObject: function(obj){ try{ if(obj.xmlVersion&&obj.firstChild!=null) return obj.xmlVersion!=''; }catch(e){ } return false; }, /** * @function isArrayObject * @description */ isArrayObject: function(obj){ try{ return (typeof(obj.push) != "undefined" && obj.push.toString().indexOf("[native code]")>0); }catch(e){ } return false; }, /** * @function isItemNative * @description */ isItemNative: function(obj){ try{ return (typeof(obj.item) != "undefined" && obj.item.toString().indexOf("[native code]")>0); }catch(e){ } return false; }, /** * @function dump * @description */ dump: function (obj, levels, level){ if(air.Introspector.isArgumentsObject(obj)&&obj.length==1) return air.Introspector.dump(obj[0]); if(typeof levels=='undefined') { levels=1; } if(typeof level=='undefined') { level=0; } try{ if(typeof obj=='undefined'){ return '[undefined]'; } if(obj==null){ return '[null]'; } var list = []; // if(air.Introspector.isXMLObject(obj)){ // disable for the moment // return; // } if(air.Introspector.isStringObject(obj) ||air.Introspector.isNumberObject(obj) ||air.Introspector.isDateObject(obj)){ if(level==0){ try{ return obj+''; }catch(e){ return e+''; }; } return''; } var isItemNative = air.Introspector.isItemNative(obj); var parseArray = air.Introspector.isArrayObject(obj)||air.Introspector.isArgumentsObject(obj)||isItemNative; var parseHash = !parseArray || isItemNative; if (parseArray){ var l = obj.length; for(var i=0;i 0;i--) prefix+=' '; var l = list.length; var strList = []; if(parseArray) strList.push(prefix+'[\r\n'); else strList.push(prefix+'{\r\n'); for(var i=0;i 0) { if(isFirstEntry) { camelizedString = oStringList[i]; isFirstEntry = false; } else { var s = oStringList[i]; camelizedString += s.charAt(0).toUpperCase() + s.substring(1); } } } return camelizedString; }, /** * @function getStyleProp * @description */ getStyleProp : function(element, prop) { var value; try { if (element.style) value = element.style[air.Introspector.camelize(prop)]; if (!value) { if (document.defaultView && document.defaultView.getComputedStyle) { var css = document.defaultView.getComputedStyle(element, null); value = css ? css.getPropertyValue(prop) : null; } else if (element.currentStyle) { value = element.currentStyle[air.Introspector.camelize(prop)]; } } } catch (e) {} return value == 'auto' ? null : value; }, /** * @function getIntProp * @description */ getIntProp : function(element, prop){ var a = parseInt(air.Introspector.getStyleProp(element, prop),10); if (isNaN(a)) return 0; return a; }, /** * @function getBorderBox * @description */ getBorderBox : function (el, doc) { doc = doc || document; if (typeof(el) == 'string') { el = doc.getElementById(el); } if (!el) { return false; } if (el.parentNode === null || air.Introspector.getStyleProp(el, 'display') == 'none') { //element must be visible to have a box return false; } var ret = {x:0, y:0, width:0, height:0}; var parent = null; var box; var str = el.nodeName; ret.x = el.offsetLeft; ret.y = el.offsetTop; ret.width = el.offsetWidth; ret.height = el.offsetHeight; parent = el.offsetParent; if (parent != el) { while (parent) { ret.x += parent.offsetLeft; ret.y += parent.offsetTop; ret.x += air.Introspector.getIntProp(parent, "border-left-width"); ret.y += air.Introspector.getIntProp(parent, "border-top-width"); str+=':'+parent.nodeName; parent = parent.offsetParent; } } // opera & (safari absolute) incorrectly account for body offsetTop switch (air.Introspector.getStyleProp(el, 'position')){ case 'absolute': ret.y -= doc.body.offsetTop; break; case 'fixed': ret.y += doc.body.scrollTop; ret.x += doc.body.scrollLeft; break; }; if (el.parentNode) parent = el.parentNode; else parent = null; if (parent!=null&&parent.nodeName){ var cas = parent.nodeName.toUpperCase(); while (parent && cas != 'HTML') { cas = parent.nodeName.toUpperCase(); ret.x -= parent.scrollLeft; ret.y -= parent.scrollTop; if (parent.parentNode) parent = parent.parentNode; else parent = null; } } /* ret.y -= el.ownerDocument.body.scrollTop; ret.x -= el.ownerDocument.body.scrollLeft; */ // adjust the margin var gi = air.Introspector.getIntProp; var btw = gi(el, "margin-top"); var blw = gi(el, "margin-left"); var bbw = gi(el, "margin-bottom"); var brw = gi(el, "margin-right"); ret.x -= blw; ret.y -= btw; ret.height += btw + bbw; ret.width += blw + brw; // air.Introspector.Console.log(ret); return ret; }, /** * --------------------------------------------------------------------------------------- */ /** * @function writeConfigFile * @description */ writeConfigFile: function(config, fromRemoteSandbox){ if(isAppSandbox){ var file = runtime.flash.filesystem.File.applicationStorageDirectory.resolvePath('AIRIntrospector'+(fromRemoteSandbox?'Remote':'')+'.cfg'); var fs = new runtime.flash.filesystem.FileStream(); fs.open(file, runtime.flash.filesystem.FileMode.WRITE); fs.writeObject(config); fs.close(); }else{ if(typeof activeWindow=='undefined'){ air.Introspector.noBridge(function(){ parentSandboxBridge.air_Introspector_writeConfigFile(config); }); }else{ activeWindow.setTimeout(function(){ try{ activeWindow.air.Introspector.writeConfigFile(config); }catch(e){} }, 0); } } }, /** * @function readConfigFile * @description */ readConfigFile: function (fromRemoteSandbox, callback){ if(isAppSandbox){ var file = runtime.flash.filesystem.File.applicationStorageDirectory.resolvePath('AIRIntrospector'+(fromRemoteSandbox?'Remote':'')+'.cfg'); if(file.exists){ var fs = new runtime.flash.filesystem.FileStream(); fs.open(file, runtime.flash.filesystem.FileMode.READ); var config = fs.readObject(); fs.close(); return config; } }else{ if(typeof activeWindow=='undefined'){ air.Introspector.noBridge(function(){ var config = parentSandboxBridge.air_Introspector_readConfigFile(); callback(config); }); }else{ activeWindow.setTimeout(function(){ try{ activeWindow.air.Introspector.readConfigFile(true, function(config){ setTimeout(function(){ callback(config); }, 0); }); }catch(e){} }, 0); } } return {}; }, /** * @function writeConsoleToClipboard * @description */ writeConsoleToClipboard: function(str){ if(isAppSandbox){ runtime.flash.desktop.Clipboard.generalClipboard.clear(); runtime.flash.desktop.Clipboard.generalClipboard.setData(runtime.flash.desktop.ClipboardFormats.TEXT_FORMAT, str, false); }else{ if(typeof activeWindow=='undefined'){ air.Introspector.noBridge(function(){ parentSandboxBridge.air_Introspector_writeConsoleToClipboard(str); }); }else{ activeWindow.setTimeout(function(){ try{ activeWindow.air.Introspector.writeConsoleToClipboard(str); }catch(e){} }); } } }, /** * @function writeConsoleToFile * @description */ writeConsoleToFile: function(str){ if(isAppSandbox){ var file = runtime.flash.filesystem.File.desktopDirectory; var self = this; file.addEventListener(runtime.flash.events.Event.SELECT, function(evt){ var newFile = evt.target; var stream = new runtime.flash.filesystem.FileStream(); stream.open(newFile, runtime.flash.filesystem.FileMode.WRITE); stream.writeUTFBytes(str); stream.close(); }); file.browseForSave('Console dump file...'); }else{ if(typeof activeWindow=='undefined'){ air.Introspector.noBridge(function(){ parentSandboxBridge.air_Introspector_writeConsoleToFile(str); }); }else{ activeWindow.setTimeout(function(){ try{ activeWindow.air.Introspector.writeConsoleToFile(str); }catch(e){} }); } } }, /** * @function noBridge * @description Alerts the user that no parent sandbox bridge is installed */ noBridge: function(callback){ try{ callback(); return; }catch(e){ air.Introspector.bridgeCallbacks.push(callback); air.Introspector.registerChildSandboxBridge(); setTimeout(function(){ throw { air_Introspector_setParentSandboxBridge: true, air_Introspector_version: air.Introspector.version , toString: function(){ return 'You need to include AIRIntrospector.js in your application sandbox.'; } }; }, 0); } }, /** * @function noChildBridge * @description Alerts the user that no child sandbox bridge is installed */ noChildBridge: function(iframe){ if(!air.Introspector.secondBridgeTry){ var iframeStr = ''; if(typeof iframe!='undefined'){ iframeStr = " Check the following iframe [id: "+iframe.id+"]"; } alert('Child sandbox bridge is not defined or has been rewritten. You need to include AIRIntrospector.js in child sandbox.'+iframeStr); air.Introspector.secondBridgeTry = true; } }, }); //------------------------------------------------------------------------------------------------------------------------------------------------------- air.Introspector.version = '1.5'; })(); air.Introspector.contentString = '\n\n\n\n ADOBE AIR HTML\/JS Application Introspector<\/title>\n