All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mgnl-resources.media.js.miframe.js Maven / Gradle / Ivy

/*
 * @class Ext.ux.ManagedIFrame
 * Version:  1.1
 * Author: Doug Hendricks. doug[always-At]theactivegroup.com
 * Copyright 2007-2008, Active Group, Inc.  All rights reserved.
 *
 ************************************************************************************
 *   This file is distributed on an AS IS BASIS WITHOUT ANY WARRANTY;
 *   without even the implied warranty of MERCHANTABILITY or
 *   FITNESS FOR A PARTICULAR PURPOSE.
 ************************************************************************************

 License: ux.ManagedIFrame and ux.ManagedIFramePanel are licensed under the terms of
 the Open Source LGPL 3.0 license.  Commercial use is permitted to the extent
 that the code/component(s) do NOT become part of another Open Source or Commercially
 licensed development library or toolkit without explicit permission.

 Donations are welcomed: http://donate.theactivegroup.com

 License details: http://www.gnu.org/licenses/lgpl.html

 * 

An Ext harness for iframe elements. Adds Ext.UpdateManager(Updater) support and a compatible 'update' method for writing content directly into an iFrames' document structure. Signals various DOM/document states as the frames content changes with 'domready', 'documentloaded', and 'exception' events. The domready event is only raised when a proper security context exists for the frame's DOM to permit modification. (ie, Updates via Updater or documents retrieved from same-domain servers). Frame sand-box permits eval/script-tag writes of javascript source. (See execScript, writeScript, and loadFunction methods for more info.) * Usage:
*


   * // Harnessed from an existing Iframe from markup:
   * var i = new Ext.ux.ManagedIFrame("myIframe");
   * // Replace the iFrames document structure with the response from the requested URL.
   * i.load("http://myserver.com/index.php", "param1=1&param2=2");

   * // Notes:  this is not the same as setting the Iframes src property !
   * // Content loaded in this fashion does not share the same document namespaces as it's parent --
   * // meaning, there (by default) will be no Ext namespace defined in it since the document is
   * // overwritten after each call to the update method, and no styleSheets.
  * 
*
* @cfg {Boolean/Object} autoCreate True to auto generate the IFRAME element, or a {@link Ext.DomHelper} config of the IFRAME to create * @cfg {String} html Any markup to be applied to the IFRAME's document content when rendered. * @cfg {Object} loadMask An {@link Ext.LoadMask} config or true to mask the iframe while using the update or setSrc methods (defaults to false). * @cfg {Object} src The src attribute to be assigned to the Iframe after initialization (overrides the autoCreate config src attribute) * @constructor * @param {Mixed} el, Config object The iframe element or it's id to harness or a valid config object. * Release: 1.1 (4/13/2008) Adds Ext.Element, CSS Selectors (query,select) fly, and CSS interface support (same-domain only) Adds blur,focus,unload events (same-domain only) */ (function(){ var EV = Ext.lib.Event; Ext.ux.ManagedIFrame = function(){ var args=Array.prototype.slice.call(arguments, 0) ,el = Ext.get(args[0]) ,config = args[0]; if(el && el.dom && el.dom.tagName == 'IFRAME'){ config = args[1] || {}; }else{ config = args[0] || args[1] || {}; el = config.autoCreate? Ext.get(Ext.DomHelper.append(config.autoCreate.parent||document.body, Ext.apply({tag:'iframe', src:(Ext.isIE&&Ext.isSecure)?Ext.SSL_SECURE_URL:''},config.autoCreate))):null; } if(!el || el.dom.tagName != 'IFRAME') return el; el.dom.name || (el.dom.name = el.dom.id); //make sure there is a valid frame name this.addEvents({ /** * @event focus * Fires when the frame gets focus. * @param {Ext.ux.ManagedIFrame} this * @param {Ext.Event} * Note: This event is only available when overwriting the iframe document using the update method and to pages * retrieved from a "same domain". * Returning false from the eventHandler [MAY] NOT cancel the event, as this event is NOT ALWAYS cancellable in all browsers. */ "focus" : true, /** * @event blur * * Fires when the frame is blurred (loses focus). * @param {Ext.ux.ManagedIFrame} this * @param {Ext.Event} * Note: This event is only available when overwriting the iframe document using the update method and to pages * retrieved from a "same domain". * Returning false from the eventHandler [MAY] NOT cancel the event, as this event is NOT ALWAYS cancellable in all browsers. */ "blur" : true, /** * @event unload * * Fires when(if) the frames window object raises the unload event * @param {Ext.ux.ManagedIFrame} this * @param {Ext.Event} * Note: This event is only available when overwriting the iframe document using the update method and to pages * retrieved from a "same domain". *Note: Opera does not raise this event. */ "unload" : true, /** * @event domready * Fires ONLY when an iFrame's Document(DOM) has reach a state where the DOM may be manipulated (ie same domain policy) * @param {Ext.ux.ManagedIFrame} this * Note: This event is only available when overwriting the iframe document using the update method and to pages * retrieved from a "same domain". * Returning false from the eventHandler stops further event (documentloaded) processing. */ "domready" : true, /** * @event documentloaded * Fires when the iFrame has reached a loaded/complete state. * @param {Ext.ux.ManagedIFrame} this */ "documentloaded" : true, /** * @event exception * Fires when the iFrame raises an error * @param {Ext.ux.ManagedIFrame} this * @param {Object/string} exception */ "exception" : true, /** * @event message * Fires upon receipt of a message generated by window.sendMessage method of the embedded Iframe.window object * @param {Ext.ux.ManagedIFrame} this * @param {object} message (members: type: {string} literal "message", * data {Mixed} [the message payload], * domain [the document domain from which the message originated ], * uri {string} the document URI of the message sender * source (Object) the window context of the message sender * tag {string} optional reference tag sent by the message sender */ "message" : true /** * Alternate event handler syntax for message:tag filtering * @event message:tag * Fires upon receipt of a message generated by window.sendMessage method * which includes a specific tag value of the embedded Iframe.window object * @param {Ext.ux.ManagedIFrame} this * @param {object} message (members: type: {string} literal "message", * data {Mixed} [the message payload], * domain [the document domain from which the message originated ], * uri {string} the document URI of the message sender * source (Object) the window context of the message sender * tag {string} optional reference tag sent by the message sender */ //"message:tagName" is supported for X-frame messaging }); if(config.listeners){ this.listeners=config.listeners; Ext.ux.ManagedIFrame.superclass.constructor.call(this); } Ext.apply(el,this); // apply this class interface ( pseudo Decorator ) el.addClass('x-managed-iframe'); if(config.style){ el.applyStyles(config.style); } el._maskEl = el.parent('.x-managed-iframe-mask')||el.parent().addClass('x-managed-iframe-mask'); Ext.apply(el,{ disableMessaging : config.disableMessaging===true ,loadMask : Ext.apply({msg:'Loading..' ,msgCls:'x-mask-loading' ,maskEl: el._maskEl ,hideOnReady:true ,disabled:!config.loadMask},config.loadMask) //Hook the Iframes loaded state handler ,_eventName : Ext.isIE?'onreadystatechange':'onload' ,_windowContext : null ,eventsFollowFrameLinks : typeof config.eventsFollowFrameLinks=='undefined'? true : config.eventsFollowFrameLinks }); el.dom[el._eventName] = el.loadHandler.createDelegate(el); if(document.addEventListener){ //for Gecko and Opera and any who might support it later Ext.EventManager.on(window,"DOMFrameContentLoaded", el.dom[el._eventName]); } var um = el.updateManager=new Ext.UpdateManager(el,true); um.showLoadIndicator= config.showLoadIndicator || false; if(config.src){ el.setSrc(config.src); }else{ var content = config.html || config.content || false; if(content){ el.update.defer(10,el,[content]); //allow frame to quiesce } } return Ext.ux.ManagedIFrame.Manager.register(el); }; var MIM = Ext.ux.ManagedIFrame.Manager = function(){ var frames = {}; return { shimCls : 'x-frame-shim', register :function(frame){ frame.manager = this; frames[frame.id] = frames[frame.dom.name] = {ref:frame, elCache:{}}; return frame; }, deRegister :function(frame){ frame._unHook(); delete frames[frame.id]; delete frames[frame.dom.name]; }, hideShims : function(){ if(!this.shimApplied)return; Ext.select('.'+this.shimCls,true).removeClass(this.shimCls+'-on'); this.shimApplied = false; }, /* Mask ALL ManagedIframes (eg. when a region-layout.splitter is on the move.)*/ showShims : function(){ if(!this.shimApplied){ this.shimApplied = true; //Activate the shimCls globally Ext.select('.'+this.shimCls,true).addClass(this.shimCls+'-on'); } }, getFrameById : function(id){ return typeof id == 'string'?(frames[id]?frames[id].ref||null:null):null; }, getFrameByName : function(name){ return this.getFrameById(name); }, //retrieve the internal frameCache object getFrameHash : function(frame){ return frame.id?frames[frame.id]:null; }, //to be called under the scope of the managing MIF eventProxy : function(e){ e = Ext.lib.Event.getEvent(e); if(!e)return; var be=e.browserEvent||e; //same-domain unloads should clear ElCache for use with the next document rendering if(e.type == 'unload'){ this._unHook(); } if(!be['eventPhase'] || (be['eventPhase'] == (be['AT_TARGET']||2))){ return this.fireEvent(e.type, e); } }, _flyweights : {}, //safe removal of embedded frame element removeNode : Ext.isIE ? function(frame, n){ frame = MIM.getFrameHash(frame); if(frame && n && n.tagName != 'BODY'){ d = frame.scratchDiv || (frame.scratchDiv = frame.getDocument().createElement('div')); d.appendChild(n); d.innerHTML = ''; } } : function(frame, n){ if(n && n.parentNode && n.tagName != 'BODY'){ n.parentNode.removeChild(n); } } } }(); MIM.showDragMask = MIM.showShims; MIM.hideDragMask = MIM.hideShims; //Provide an Ext.Element interface to frame document elements MIM.El =function(frame, el, forceNew){ var frameObj; frame = (frameObj = MIM.getFrameHash(frame))?frameObj.ref:null ; if(!frame ){ return null; } var elCache = frameObj.elCache || (frameObj.elCache = {}); var dom = frame.getDom(el); if(!dom){ // invalid id/element return null; } var id = dom.id; if(forceNew !== true && id && elCache[id]){ // element object already exists return elCache[id]; } /** * The DOM element * @type HTMLElement */ this.dom = dom; /** * The DOM element ID * @type String */ this.id = id || Ext.id(dom); }; MIM.El.get =function(frame, el){ var ex, elm, id, doc; if(!frame || !el ){ return null; } var frameObj; frame = (frameObj = MIM.getFrameHash(frame))?frameObj.ref:null ; if(!frame ){ return null;} var elCache = frameObj.elCache || (frameObj.elCache = {} ); if(!(doc = frame.getDocument())){ return null; } if(typeof el == "string"){ // element id if(!(elm = frame.getDom(el))){ return null; } if(ex = elCache[el]){ ex.dom = elm; }else{ ex = elCache[el] = new MIM.El(frame, elm); } return ex; }else if(el.tagName){ // dom element if(!(id = el.id)){ id = Ext.id(el); } if(ex = elCache[id]){ ex.dom = el; }else{ ex = elCache[id] = new MIM.El(frame, el); } return ex; }else if(el instanceof MIM.El){ if(el != frameObj.docEl){ el.dom = frame.getDom(el.id) || el.dom; // refresh dom element in case no longer valid, // catch case where it hasn't been appended elCache[el.id] = el; // in case it was created directly with Element(), let's cache it } return el; }else if(el.isComposite){ return el; }else if(Ext.isArray(el)){ return frame.select(el); }else if(el == doc){ // create a bogus element object representing the document object if(!frameObj.docEl){ var f = function(){}; f.prototype = MIM.El.prototype; frameObj.docEl = new f(); frameObj.docEl.dom = doc; } return frameObj.docEl; } return null; }; Ext.apply(MIM.El.prototype,Ext.Element.prototype); Ext.extend(Ext.ux.ManagedIFrame , Ext.util.Observable, { src : null , /** * Sets the embedded Iframe src property. * @param {String/Function} url (Optional) A string or reference to a Function that returns a URI string when called * @param {Boolean} discardUrl (Optional) If not passed as false the URL of this action becomes the default SRC attribute for * this iframe, and will be subsequently used in future setSrc calls (emulates autoRefresh by calling setSrc without params). * Note: invoke the function with no arguments to refresh the iframe based on the current src value. */ setSrc : function(url, discardUrl, callback){ var reset = Ext.isIE&&Ext.isSecure?Ext.SSL_SECURE_URL:''; var src = url || this.src || reset; if(Ext.isOpera){ this.dom.src = reset; } this._windowContext = null; this._unHook(); this._callBack = callback || false; this.showMask(); (function(){ var s = typeof src == 'function'?src()||'':src; try{ this._frameAction = true; //signal listening now this.dom.src = s; this.frameInit= true; //control initial event chatter this.checkDOM(); }catch(ex){ this.fireEvent('exception', this, ex); } }).defer(10,this); if(discardUrl !== true){ this.src = src; } return this; }, reset : function(src, callback){ this.setSrc(src || (Ext.isIE&&Ext.isSecure?Ext.SSL_SECURE_URL:''),true,callback); }, //Private: script removal RegeXp scriptRE : /(?:)((\n|\r|.)*?)(?:<\/script>)/gi , /* * Write(replacing) string content into the IFrames document structure * @param {String} content The new content * @param {Boolean} loadScripts (optional) true to also render and process embedded scripts * @param {Function} callback (optional) Callback when update is complete. */ update : function(content,loadScripts,callback){ loadScripts = loadScripts || this.getUpdateManager().loadScripts || false; content = Ext.DomHelper.markup(content||''); content = loadScripts===true ? content:content.replace(this.scriptRE , ""); var doc; if(doc = this.getDocument()){ this._frameAction = !!content.length; this._windowContext = this.src = null; this._callBack = callback || false; this._unHook(); this.showMask(); doc.open(); doc.write(content); doc.close(); this.frameInit= true; //control initial event chatter if(this._frameAction){ this.checkDOM(); } else { this.hideMask(true); if(this._callBack)this._callBack(); } }else{ this.hideMask(true); if(this._callBack)this._callBack(); } return this; }, /* Enables/disables x-frame messaging interface */ disableMessaging : true, //Private, frame messaging interface (for same-domain-policy frames only) _XFrameMessaging : function(){ //each tag gets a hash queue ($ = no tag ). var tagStack = {'$' : [] }; var isEmpty = function(v, allowBlank){ return v === null || v === undefined || (!allowBlank ? v === '' : false); }; window.sendMessage = function(message, tag, origin ){ var MIF; if(MIF = arguments.callee.manager){ if(message._fromHost){ var fn, result; //only raise matching-tag handlers var compTag= message.tag || tag || null; var mstack = !isEmpty(compTag)? tagStack[compTag.toLowerCase()]||[] : tagStack["$"]; for(var i=0,l=mstack.length;i Note: will only work after a successful iframe.(Updater) update * or after same-domain document has been hooked, otherwise an exception is raised. */ ,execScript: function(block, useDOM){ try{ if(this.domWritable()){ if(useDOM){ this.writeScript(block); }else{ return this._windowContext.eval(block); } }else{ throw 'execScript:non-secure context' } }catch(ex){ this.fireEvent('exception', this, ex); return false; } return true; } /* * write a