src/cm/media/js/lib/yui/yui3-3.15.0/build/frame/frame-debug.js
changeset 602 e16a97fb364a
equal deleted inserted replaced
601:d334a616c023 602:e16a97fb364a
       
     1 YUI.add('frame', function (Y, NAME) {
       
     2 
       
     3     /*jshint maxlen: 500 */
       
     4     /**
       
     5      * Creates a wrapper around an iframe. It loads the content either from a local
       
     6      * file or from script and creates a local YUI instance bound to that new window and document.
       
     7      * @class Frame
       
     8      * @for Frame
       
     9      * @extends Base
       
    10      * @constructor
       
    11      * @module editor
       
    12      * @submodule frame
       
    13      */
       
    14 
       
    15     var Lang = Y.Lang,
       
    16 
       
    17         EVENT_CONTENT_READY = 'contentready',
       
    18 
       
    19         HOST = 'host',
       
    20 
       
    21     Frame = function() {
       
    22         Frame.superclass.constructor.apply(this, arguments);
       
    23     };
       
    24 
       
    25 
       
    26     Y.extend(Frame, Y.Plugin.Base, {
       
    27         /**
       
    28         * @private
       
    29         * @property _ready
       
    30         * @description Internal reference set when the content is ready.
       
    31         * @type Boolean
       
    32         */
       
    33         _ready: null,
       
    34         /**
       
    35         * @private
       
    36         * @property _rendered
       
    37         * @description Internal reference set when render is called.
       
    38         * @type Boolean
       
    39         */
       
    40         _rendered: null,
       
    41         /**
       
    42         * @private
       
    43         * @property _iframe
       
    44         * @description Internal Node reference to the iFrame or the window
       
    45         * @type Node
       
    46         */
       
    47         _iframe: null,
       
    48         /**
       
    49         * @private
       
    50         * @property _instance
       
    51         * @description Internal reference to the YUI instance bound to the iFrame or window
       
    52         * @type YUI
       
    53         */
       
    54         _instance: null,
       
    55         /**
       
    56         * @private
       
    57         * @method _create
       
    58         * @description Create the iframe or Window and get references to the Document & Window
       
    59         * @return {Object} Hash table containing references to the new Document & Window
       
    60         */
       
    61         _create: function(cb) {
       
    62             var res, html = '', timer,
       
    63                 //if the src attr is different than the default, don't create the document
       
    64                 create = (this.get('src') === Frame.ATTRS.src.value),
       
    65                 extra_css = ((this.get('extracss')) ? '<style id="extra_css">' + this.get('extracss') + '</style>' : '');
       
    66 
       
    67             this._iframe = Y.one(Y.config.doc.createElement('iframe'));
       
    68             this._iframe.setAttrs(Frame.IFRAME_ATTRS);
       
    69 
       
    70             this._iframe.setStyle('visibility', 'hidden');
       
    71             this._iframe.set('src', this.get('src'));
       
    72             this.get('container').append(this._iframe);
       
    73             this._iframe.set('height', '99%');
       
    74 
       
    75             if (create) {
       
    76                 Y.log('Creating the document from javascript', 'info', 'frame');
       
    77                 html = Y.Lang.sub(Frame.PAGE_HTML, {
       
    78                     DIR: this.get('dir'),
       
    79                     LANG: this.get('lang'),
       
    80                     TITLE: this.get('title'),
       
    81                     META: Frame.META,
       
    82                     LINKED_CSS: this.get('linkedcss'),
       
    83                     CONTENT: this.get('content'),
       
    84                     BASE_HREF: this.get('basehref'),
       
    85                     DEFAULT_CSS: Frame.DEFAULT_CSS,
       
    86                     EXTRA_CSS: extra_css
       
    87                 });
       
    88                 if (Y.config.doc.compatMode !== 'BackCompat') {
       
    89                     Y.log('Adding Doctype to frame: ' + Frame.getDocType(), 'info', 'frame');
       
    90 
       
    91                     //html = Frame.DOC_TYPE + "\n" + html;
       
    92                     html = Frame.getDocType() + "\n" + html;
       
    93                 } else {
       
    94                     Y.log('DocType skipped because we are in BackCompat Mode.', 'warn', 'frame');
       
    95                 }
       
    96 
       
    97                 Y.log('Injecting content into iframe', 'info', 'frame');
       
    98             }
       
    99 
       
   100             res = this._resolveWinDoc();
       
   101 
       
   102             if (html) {
       
   103                 Y.log('Writing HTML to new document', 'info', 'frame');
       
   104                 res.doc.open();
       
   105                 res.doc.write(html);
       
   106                 res.doc.close();
       
   107             }
       
   108 
       
   109             if (!res.doc.documentElement) {
       
   110                 Y.log('document.documentElement was not found, running timer', 'warn', 'frame');
       
   111                 timer = Y.later(1, this, function() {
       
   112                     if (res.doc && res.doc.documentElement) {
       
   113                         Y.log('document.documentElement found inside timer', 'info', 'frame');
       
   114                         cb(res);
       
   115                         timer.cancel();
       
   116                     }
       
   117                 }, null, true);
       
   118             } else {
       
   119                 Y.log('document.documentElement found', 'info', 'frame');
       
   120                 cb(res);
       
   121             }
       
   122 
       
   123         },
       
   124         /**
       
   125         * @private
       
   126         * @method _resolveWinDoc
       
   127         * @description Resolves the document and window from an iframe or window instance
       
   128         * @param {Object} c The YUI Config to add the window and document to
       
   129         * @return {Object} Object hash of window and document references, if a YUI config was passed, it is returned.
       
   130         */
       
   131         _resolveWinDoc: function(c) {
       
   132             var config = (c) ? c : {};
       
   133             config.win = Y.Node.getDOMNode(this._iframe.get('contentWindow'));
       
   134             config.doc = Y.Node.getDOMNode(this._iframe.get('contentWindow.document'));
       
   135             if (!config.doc) {
       
   136                 config.doc = Y.config.doc;
       
   137             }
       
   138             if (!config.win) {
       
   139                 config.win = Y.config.win;
       
   140             }
       
   141             return config;
       
   142         },
       
   143         /**
       
   144         * @private
       
   145         * @method _onDomEvent
       
   146         * @description Generic handler for all DOM events fired by the iframe or window. This handler
       
   147         * takes the current EventFacade and augments it to fire on the Frame host. It adds two new properties
       
   148         * to the EventFacade called frameX and frameY which adds the scroll and xy position of the iframe
       
   149         * to the original pageX and pageY of the event so external nodes can be positioned over the frame.
       
   150         * @param {EventFacade} e
       
   151         */
       
   152         _onDomEvent: function(e) {
       
   153             var xy, node;
       
   154 
       
   155             if (!Y.Node.getDOMNode(this._iframe)) {
       
   156                 //The iframe is null for some reason, bail on sending events.
       
   157                 return;
       
   158             }
       
   159 
       
   160             //Y.log('onDOMEvent: ' + e.type, 'info', 'frame');
       
   161             e.frameX = e.frameY = 0;
       
   162 
       
   163             if (e.pageX > 0 || e.pageY > 0) {
       
   164                 if (e.type.substring(0, 3) !== 'key') {
       
   165                     node = this._instance.one('win');
       
   166                     xy = this._iframe.getXY();
       
   167                     e.frameX = xy[0] + e.pageX - node.get('scrollLeft');
       
   168                     e.frameY = xy[1] + e.pageY - node.get('scrollTop');
       
   169                 }
       
   170             }
       
   171 
       
   172             e.frameTarget = e.target;
       
   173             e.frameCurrentTarget = e.currentTarget;
       
   174             e.frameEvent = e;
       
   175 
       
   176             this.fire('dom:' + e.type, e);
       
   177         },
       
   178         initializer: function() {
       
   179             var host = this.get(HOST);
       
   180 
       
   181             if (host) {
       
   182                 host.frame = this;
       
   183             }
       
   184 
       
   185             this.publish('ready', {
       
   186                 emitFacade: true,
       
   187                 defaultFn: this._defReadyFn
       
   188             });
       
   189         },
       
   190         destructor: function() {
       
   191             var inst = this.getInstance();
       
   192 
       
   193             inst.one('doc').detachAll();
       
   194             inst = null;
       
   195             this._iframe.remove();
       
   196         },
       
   197         /**
       
   198         * @private
       
   199         * @method _DOMPaste
       
   200         * @description Simple pass thru handler for the paste event so we can do content cleanup
       
   201         * @param {EventFacade} e
       
   202         */
       
   203         _DOMPaste: function(e) {
       
   204             var inst = this.getInstance(),
       
   205                 data = '', win = inst.config.win;
       
   206 
       
   207             if (e._event.originalTarget) {
       
   208                 data = e._event.originalTarget;
       
   209             }
       
   210             if (e._event.clipboardData) {
       
   211                 data = e._event.clipboardData.getData('Text');
       
   212             }
       
   213 
       
   214             if (win.clipboardData) {
       
   215                 data = win.clipboardData.getData('Text');
       
   216                 if (data === '') { // Could be empty, or failed
       
   217                     // Verify failure
       
   218                     if (!win.clipboardData.setData('Text', data)) {
       
   219                         data = null;
       
   220                     }
       
   221                 }
       
   222             }
       
   223 
       
   224 
       
   225             e.frameTarget = e.target;
       
   226             e.frameCurrentTarget = e.currentTarget;
       
   227             e.frameEvent = e;
       
   228 
       
   229             if (data) {
       
   230                 e.clipboardData = {
       
   231                     data: data,
       
   232                     getData: function() {
       
   233                         return data;
       
   234                     }
       
   235                 };
       
   236             } else {
       
   237                 Y.log('Failed to collect clipboard data', 'warn', 'frame');
       
   238                 e.clipboardData = null;
       
   239             }
       
   240 
       
   241             this.fire('dom:paste', e);
       
   242         },
       
   243         /**
       
   244         * @private
       
   245         * @method _defReadyFn
       
   246         * @description Binds DOM events, sets the iframe to visible and fires the ready event
       
   247         */
       
   248         _defReadyFn: function() {
       
   249             var inst = this.getInstance();
       
   250 
       
   251             Y.each(Frame.DOM_EVENTS, function(v, k) {
       
   252                 var fn = Y.bind(this._onDomEvent, this),
       
   253                     kfn = ((Y.UA.ie && Frame.THROTTLE_TIME > 0) ? Y.throttle(fn, Frame.THROTTLE_TIME) : fn);
       
   254 
       
   255                 if (!inst.Node.DOM_EVENTS[k]) {
       
   256                     inst.Node.DOM_EVENTS[k] = 1;
       
   257                 }
       
   258                 if (v === 1) {
       
   259                     if (k !== 'focus' && k !== 'blur' && k !== 'paste') {
       
   260                         //Y.log('Adding DOM event to frame: ' + k, 'info', 'frame');
       
   261                         if (k.substring(0, 3) === 'key') {
       
   262                             //Throttle key events in IE
       
   263                             inst.on(k, kfn, inst.config.doc);
       
   264                         } else {
       
   265                             inst.on(k, fn, inst.config.doc);
       
   266                         }
       
   267                     }
       
   268                 }
       
   269             }, this);
       
   270 
       
   271             inst.Node.DOM_EVENTS.paste = 1;
       
   272 
       
   273             inst.on('paste', Y.bind(this._DOMPaste, this), inst.one('body'));
       
   274 
       
   275             //Adding focus/blur to the window object
       
   276             inst.on('focus', Y.bind(this._onDomEvent, this), inst.config.win);
       
   277             inst.on('blur', Y.bind(this._onDomEvent, this), inst.config.win);
       
   278 
       
   279             inst.__use = inst.use;
       
   280             inst.use = Y.bind(this.use, this);
       
   281             this._iframe.setStyles({
       
   282                 visibility: 'inherit'
       
   283             });
       
   284             inst.one('body').setStyle('display', 'block');
       
   285         },
       
   286         /**
       
   287         * It appears that having a BR tag anywhere in the source "below" a table with a percentage width (in IE 7 & 8)
       
   288         * if there is any TEXTINPUT's outside the iframe, the cursor will rapidly flickr and the CPU would occasionally
       
   289         * spike. This method finds all <BR>'s below the sourceIndex of the first table. Does some checks to see if they
       
   290         * can be modified and replaces then with a <WBR> so the layout will remain in tact, but the flickering will
       
   291         * no longer happen.
       
   292         * @method _fixIECursors
       
   293         * @private
       
   294         */
       
   295         _fixIECursors: function() {
       
   296             var inst = this.getInstance(),
       
   297                 tables = inst.all('table'),
       
   298                 brs = inst.all('br'), si;
       
   299 
       
   300             if (tables.size() && brs.size()) {
       
   301                 //First Table
       
   302                 si = tables.item(0).get('sourceIndex');
       
   303                 brs.each(function(n) {
       
   304                     var p = n.get('parentNode'),
       
   305                         c = p.get('children'), b = p.all('>br');
       
   306 
       
   307                     if (p.test('div')) {
       
   308                         if (c.size() > 2) {
       
   309                             n.replace(inst.Node.create('<wbr>'));
       
   310                         } else {
       
   311                             if (n.get('sourceIndex') > si) {
       
   312                                 if (b.size()) {
       
   313                                     n.replace(inst.Node.create('<wbr>'));
       
   314                                 }
       
   315                             } else {
       
   316                                 if (b.size() > 1) {
       
   317                                     n.replace(inst.Node.create('<wbr>'));
       
   318                                 }
       
   319                             }
       
   320                         }
       
   321                     }
       
   322 
       
   323                 });
       
   324             }
       
   325         },
       
   326         /**
       
   327         * @private
       
   328         * @method _onContentReady
       
   329         * @description Called once the content is available in the frame/window and calls the final use call
       
   330         * on the internal instance so that the modules are loaded properly.
       
   331         */
       
   332         _onContentReady: function(e) {
       
   333             if (!this._ready) {
       
   334                 this._ready = true;
       
   335                 var inst = this.getInstance(),
       
   336                     args = Y.clone(this.get('use'));
       
   337 
       
   338                 this.fire('contentready');
       
   339 
       
   340                 Y.log('On available for body of iframe', 'info', 'frame');
       
   341                 if (e) {
       
   342                     inst.config.doc = Y.Node.getDOMNode(e.target);
       
   343                 }
       
   344                 //TODO Circle around and deal with CSS loading...
       
   345                 args.push(Y.bind(function() {
       
   346                     Y.log('Callback from final internal use call', 'info', 'frame');
       
   347                     if (inst.EditorSelection) {
       
   348                         inst.EditorSelection.DEFAULT_BLOCK_TAG = this.get('defaultblock');
       
   349                     }
       
   350                     //Moved to here so that the iframe is ready before allowing editing..
       
   351                     if (this.get('designMode')) {
       
   352                         if(Y.UA.ie) {
       
   353                             inst.config.doc.body.contentEditable = 'true';
       
   354                             this._ieSetBodyHeight();
       
   355                             inst.on('keyup', Y.bind(this._ieSetBodyHeight, this), inst.config.doc);
       
   356                         } else {
       
   357                             inst.config.doc.designMode = 'on';
       
   358                         }
       
   359                     }
       
   360                     this.fire('ready');
       
   361                 }, this));
       
   362                 Y.log('Calling use on internal instance: ' + args, 'info', 'frame');
       
   363                 inst.use.apply(inst, args);
       
   364 
       
   365                 inst.one('doc').get('documentElement').addClass('yui-js-enabled');
       
   366             }
       
   367         },
       
   368         _ieHeightCounter: null,
       
   369         /**
       
   370         * Internal method to set the height of the body to the height of the document in IE.
       
   371         * With contenteditable being set, the document becomes unresponsive to clicks, this
       
   372         * method expands the body to be the height of the document so that doesn't happen.
       
   373         * @private
       
   374         * @method _ieSetBodyHeight
       
   375         */
       
   376         _ieSetBodyHeight: function(e) {
       
   377             if (!this._ieHeightCounter) {
       
   378                 this._ieHeightCounter = 0;
       
   379             }
       
   380             this._ieHeightCounter++;
       
   381             var run = false, inst, h, bh;
       
   382             if (!e) {
       
   383                 run = true;
       
   384             }
       
   385             if (e) {
       
   386                 switch (e.keyCode) {
       
   387                     case 8:
       
   388                     case 13:
       
   389                         run = true;
       
   390                         break;
       
   391                 }
       
   392                 if (e.ctrlKey || e.shiftKey) {
       
   393                     run = true;
       
   394                 }
       
   395             }
       
   396             if (run) {
       
   397                 try {
       
   398                     inst = this.getInstance();
       
   399                     h = this._iframe.get('offsetHeight');
       
   400                     bh = inst.config.doc.body.scrollHeight;
       
   401                     if (h > bh) {
       
   402                         h = (h - 15) + 'px';
       
   403                         inst.config.doc.body.style.height = h;
       
   404                     } else {
       
   405                         inst.config.doc.body.style.height = 'auto';
       
   406                     }
       
   407                 } catch (e) {
       
   408                     if (this._ieHeightCounter < 100) {
       
   409                         Y.later(200, this, this._ieSetBodyHeight);
       
   410                     } else {
       
   411                         Y.log('Failed to set body height in IE', 'error', 'frame');
       
   412                     }
       
   413                 }
       
   414             }
       
   415         },
       
   416         /**
       
   417         * @private
       
   418         * @method _resolveBaseHref
       
   419         * @description Resolves the basehref of the page the frame is created on. Only applies to dynamic content.
       
   420         * @param {String} href The new value to use, if empty it will be resolved from the current url.
       
   421         * @return {String}
       
   422         */
       
   423         _resolveBaseHref: function(href) {
       
   424             if (!href || href === '') {
       
   425                 href = Y.config.doc.location.href;
       
   426                 if (href.indexOf('?') !== -1) { //Remove the query string
       
   427                     href = href.substring(0, href.indexOf('?'));
       
   428                 }
       
   429                 href = href.substring(0, href.lastIndexOf('/')) + '/';
       
   430             }
       
   431             return href;
       
   432         },
       
   433         /**
       
   434         * @private
       
   435         * @method _getHTML
       
   436         * @description Get the content from the iframe
       
   437         * @param {String} html The raw HTML from the body of the iframe.
       
   438         * @return {String}
       
   439         */
       
   440         _getHTML: function(html) {
       
   441             if (this._ready) {
       
   442                 var inst = this.getInstance();
       
   443                 html = inst.one('body').get('innerHTML');
       
   444             }
       
   445             return html;
       
   446         },
       
   447         /**
       
   448         * @private
       
   449         * @method _setHTML
       
   450         * @description Set the content of the iframe
       
   451         * @param {String} html The raw HTML to set the body of the iframe to.
       
   452         * @return {String}
       
   453         */
       
   454         _setHTML: function(html) {
       
   455             if (this._ready) {
       
   456                 var inst = this.getInstance();
       
   457                 inst.one('body').set('innerHTML', html);
       
   458             } else {
       
   459                 this.once(EVENT_CONTENT_READY, Y.bind(this._setHTML, this, html));
       
   460             }
       
   461 
       
   462             return html;
       
   463         },
       
   464         /**
       
   465         * @private
       
   466         * @method _getLinkedCSS
       
   467         * @description Get the linked CSS on the instance.
       
   468         */
       
   469         _getLinkedCSS: function(urls) {
       
   470             if (!Y.Lang.isArray(urls)) {
       
   471                 urls = [urls];
       
   472             }
       
   473             var str = '';
       
   474             if (!this._ready) {
       
   475                 Y.each(urls, function(v) {
       
   476                     if (v) {
       
   477                         str += '<link rel="stylesheet" href="' + v + '" type="text/css">';
       
   478                     }
       
   479                 });
       
   480             } else {
       
   481                 str = urls;
       
   482             }
       
   483             return str;
       
   484         },
       
   485         /**
       
   486         * @private
       
   487         * @method _setLinkedCSS
       
   488         * @description Sets the linked CSS on the instance..
       
   489         */
       
   490         _setLinkedCSS: function(css) {
       
   491             if (this._ready) {
       
   492                 var inst = this.getInstance();
       
   493                 inst.Get.css(css);
       
   494             }
       
   495             return css;
       
   496         },
       
   497         /**
       
   498         * @private
       
   499         * @method _setExtraCSS
       
   500         * @description Set's the extra CSS on the instance..
       
   501         */
       
   502         _setExtraCSS: function(css) {
       
   503             if (this._ready) {
       
   504                 var inst = this.getInstance(),
       
   505                     node = inst.one('#extra_css');
       
   506 
       
   507                 node.remove();
       
   508                 inst.one('head').append('<style id="extra_css">' + css + '</style>');
       
   509             } else {
       
   510                 //This needs to be wrapped in a contentready callback for the !_ready state
       
   511                 this.once(EVENT_CONTENT_READY, Y.bind(this._setExtraCSS, this, css));
       
   512             }
       
   513 
       
   514             return css;
       
   515         },
       
   516         /**
       
   517         * @private
       
   518         * @method _instanceLoaded
       
   519         * @description Called from the first YUI instance that sets up the internal instance.
       
   520         * This loads the content into the window/frame and attaches the contentready event.
       
   521         * @param {YUI} inst The internal YUI instance bound to the frame/window
       
   522         */
       
   523         _instanceLoaded: function(inst) {
       
   524             this._instance = inst;
       
   525             this._onContentReady();
       
   526 
       
   527             var doc = this._instance.config.doc;
       
   528 
       
   529             if (this.get('designMode')) {
       
   530                 if (!Y.UA.ie) {
       
   531                     try {
       
   532                         //Force other browsers into non CSS styling
       
   533                         doc.execCommand('styleWithCSS', false, false);
       
   534                         doc.execCommand('insertbronreturn', false, false);
       
   535                     } catch (err) {}
       
   536                 }
       
   537             }
       
   538         },
       
   539         //BEGIN PUBLIC METHODS
       
   540         /**
       
   541         * @method use
       
   542         * @description This is a scoped version of the normal YUI.use method & is bound to this frame/window.
       
   543         * At setup, the inst.use method is mapped to this method.
       
   544         */
       
   545         use: function() {
       
   546             Y.log('Calling augmented use after ready', 'info', 'frame');
       
   547             var inst = this.getInstance(),
       
   548                 args = Y.Array(arguments),
       
   549                 cb = false;
       
   550 
       
   551             if (Y.Lang.isFunction(args[args.length - 1])) {
       
   552                 cb = args.pop();
       
   553             }
       
   554             if (cb) {
       
   555                 args.push(function() {
       
   556                     Y.log('Internal callback from augmented use', 'info', 'frame');
       
   557                     cb.apply(inst, arguments);
       
   558 
       
   559                 });
       
   560             }
       
   561             
       
   562             return inst.__use.apply(inst, args);
       
   563         },
       
   564         /**
       
   565         * @method delegate
       
   566         * @description A delegate method passed to the instance's delegate method
       
   567         * @param {String} type The type of event to listen for
       
   568         * @param {Function} fn The method to attach
       
   569         * @param {String} cont The container to act as a delegate, if no "sel" passed, the body is assumed as the container.
       
   570         * @param {String} sel The selector to match in the event (optional)
       
   571         * @return {EventHandle} The Event handle returned from Y.delegate
       
   572         */
       
   573         delegate: function(type, fn, cont, sel) {
       
   574             var inst = this.getInstance();
       
   575             if (!inst) {
       
   576                 Y.log('Delegate events can not be attached until after the ready event has fired.', 'error', 'iframe');
       
   577                 return false;
       
   578             }
       
   579             if (!sel) {
       
   580                 sel = cont;
       
   581                 cont = 'body';
       
   582             }
       
   583             return inst.delegate(type, fn, cont, sel);
       
   584         },
       
   585         /**
       
   586         * @method getInstance
       
   587         * @description Get a reference to the internal YUI instance.
       
   588         * @return {YUI} The internal YUI instance
       
   589         */
       
   590         getInstance: function() {
       
   591             return this._instance;
       
   592         },
       
   593         /**
       
   594         * @method render
       
   595         * @description Render the iframe into the container config option or open the window.
       
   596         * @param {String/HTMLElement/Node} node The node to render to
       
   597         * @return {Frame}
       
   598         * @chainable
       
   599         */
       
   600         render: function(node) {
       
   601             if (this._rendered) {
       
   602                 Y.log('Frame already rendered.', 'warn', 'frame');
       
   603                 return this;
       
   604             }
       
   605             this._rendered = true;
       
   606             if (node) {
       
   607                 this.set('container', node);
       
   608             }
       
   609 
       
   610             this._create(Y.bind(function(res) {
       
   611 
       
   612                 var inst, timer,
       
   613                     cb = Y.bind(function(i) {
       
   614                         Y.log('Internal instance loaded with node-base', 'info', 'frame');
       
   615                         this._instanceLoaded(i);
       
   616                     }, this),
       
   617                     args = Y.clone(this.get('use')),
       
   618                     config = {
       
   619                         debug: false,
       
   620                         win: res.win,
       
   621                         doc: res.doc
       
   622                     },
       
   623                     fn = Y.bind(function() {
       
   624                         Y.log('New Modules Loaded into main instance', 'info', 'frame');
       
   625                         config = this._resolveWinDoc(config);
       
   626                         inst = YUI(config);
       
   627                         inst.host = this.get(HOST); //Cross reference to Editor
       
   628                         inst.log = Y.log; //Dump the instance logs to the parent instance.
       
   629 
       
   630                         Y.log('Creating new internal instance with node-base only', 'info', 'frame');
       
   631                         try {
       
   632                             inst.use('node-base', cb);
       
   633                             if (timer) {
       
   634                                 clearInterval(timer);
       
   635                             }
       
   636                         } catch (e) {
       
   637                             timer = setInterval(function() {
       
   638                                 Y.log('[TIMER] Internal use call failed, retrying', 'info', 'frame');
       
   639                                 fn();
       
   640                             }, 350);
       
   641                             Y.log('Internal use call failed, retrying', 'info', 'frame');
       
   642                         }
       
   643                     }, this);
       
   644 
       
   645                 args.push(fn);
       
   646 
       
   647                 Y.log('Adding new modules to main instance: ' + args, 'info', 'frame');
       
   648                 Y.use.apply(Y, args);
       
   649 
       
   650             }, this));
       
   651 
       
   652             return this;
       
   653         },
       
   654         /**
       
   655         * @private
       
   656         * @method _handleFocus
       
   657         * @description Does some tricks on focus to set the proper cursor position.
       
   658         */
       
   659         _handleFocus: function() {
       
   660             var inst = this.getInstance(),
       
   661                 sel = new inst.EditorSelection(),
       
   662                 n, c, b, par;
       
   663 
       
   664             if (sel.anchorNode) {
       
   665                 Y.log('_handleFocus being called..', 'info', 'frame');
       
   666                 n = sel.anchorNode;
       
   667 
       
   668                 if (n.test('p') && n.get('innerHTML') === '') {
       
   669                     n = n.get('parentNode');
       
   670                 }
       
   671                 c = n.get('childNodes');
       
   672 
       
   673                 if (c.size()) {
       
   674                     if (c.item(0).test('br')) {
       
   675                         sel.selectNode(n, true, false);
       
   676                     } else if (c.item(0).test('p')) {
       
   677                         n = c.item(0).one('br.yui-cursor');
       
   678                         if (n) {
       
   679                             n = n.get('parentNode');
       
   680                         }
       
   681                         if (!n) {
       
   682                             n = c.item(0).get('firstChild');
       
   683                         }
       
   684                         if (!n) {
       
   685                             n = c.item(0);
       
   686                         }
       
   687                         if (n) {
       
   688                             sel.selectNode(n, true, false);
       
   689                         }
       
   690                     } else {
       
   691                         b = inst.one('br.yui-cursor');
       
   692                         if (b) {
       
   693                             par = b.get('parentNode');
       
   694                             if (par) {
       
   695                                 sel.selectNode(par, true, false);
       
   696                             }
       
   697                         }
       
   698                     }
       
   699                 }
       
   700             }
       
   701         },
       
   702         /**
       
   703         * Validates linkedcss property
       
   704         *
       
   705         * @method _validateLinkedCSS
       
   706         * @private
       
   707         */
       
   708         _validateLinkedCSS: function(value) {
       
   709             return Lang.isString(value) || Lang.isArray(value);
       
   710         },
       
   711         /**
       
   712         * @method focus
       
   713         * @description Set the focus to the iframe
       
   714         * @param {Function} fn Callback function to execute after focus happens
       
   715         * @return {Frame}
       
   716         * @chainable
       
   717         */
       
   718         focus: function(fn) {
       
   719             if (Y.UA.ie && Y.UA.ie < 9) {
       
   720                 try {
       
   721                     Y.one('win').focus();
       
   722                     if (this.getInstance()) {
       
   723                         if (this.getInstance().one('win')) {
       
   724                             this.getInstance().one('win').focus();
       
   725                         }
       
   726                     }
       
   727                 } catch (ierr) {
       
   728                     Y.log('Frame focus failed', 'warn', 'frame');
       
   729                 }
       
   730                 if (fn === true) {
       
   731                     this._handleFocus();
       
   732                 }
       
   733                 if (Y.Lang.isFunction(fn)) {
       
   734                     fn();
       
   735                 }
       
   736             } else {
       
   737                 try {
       
   738                     Y.one('win').focus();
       
   739                     Y.later(100, this, function() {
       
   740                         if (this.getInstance()) {
       
   741                             if (this.getInstance().one('win')) {
       
   742                                 this.getInstance().one('win').focus();
       
   743                             }
       
   744                         }
       
   745                         if (fn === true) {
       
   746                             this._handleFocus();
       
   747                         }
       
   748                         if (Y.Lang.isFunction(fn)) {
       
   749                             fn();
       
   750                         }
       
   751                     });
       
   752                 } catch (ferr) {
       
   753                     Y.log('Frame focus failed', 'warn', 'frame');
       
   754                 }
       
   755             }
       
   756             return this;
       
   757         },
       
   758         /**
       
   759         * @method show
       
   760         * @description Show the iframe instance
       
   761         * @return {Frame}
       
   762         * @chainable
       
   763         */
       
   764         show: function() {
       
   765             this._iframe.setStyles({
       
   766                 position: 'static',
       
   767                 left: ''
       
   768             });
       
   769             if (Y.UA.gecko) {
       
   770                 try {
       
   771                     if (this.getInstance()) {
       
   772                         this.getInstance().config.doc.designMode = 'on';
       
   773                     }
       
   774                 } catch (e) { }
       
   775                 this.focus();
       
   776             }
       
   777             return this;
       
   778         },
       
   779         /**
       
   780         * @method hide
       
   781         * @description Hide the iframe instance
       
   782         * @return {Frame}
       
   783         * @chainable
       
   784         */
       
   785         hide: function() {
       
   786             this._iframe.setStyles({
       
   787                 position: 'absolute',
       
   788                 left: '-999999px'
       
   789             });
       
   790             return this;
       
   791         }
       
   792     }, {
       
   793         /**
       
   794         * @static
       
   795         * @property THROTTLE_TIME
       
   796         * @description The throttle time for key events in IE
       
   797         * @type Number
       
   798         * @default 100
       
   799         */
       
   800         THROTTLE_TIME: 100,
       
   801         /**
       
   802         * @static
       
   803         * @property DOM_EVENTS
       
   804         * @description The DomEvents that the frame automatically attaches and bubbles
       
   805         * @type Object
       
   806         */
       
   807         DOM_EVENTS: {
       
   808             dblclick: 1,
       
   809             click: 1,
       
   810             paste: 1,
       
   811             mouseup: 1,
       
   812             mousedown: 1,
       
   813             keyup: 1,
       
   814             keydown: 1,
       
   815             keypress: 1,
       
   816             activate: 1,
       
   817             deactivate: 1,
       
   818             beforedeactivate: 1,
       
   819             focusin: 1,
       
   820             focusout: 1
       
   821         },
       
   822 
       
   823         /**
       
   824         * @static
       
   825         * @property DEFAULT_CSS
       
   826         * @description The default css used when creating the document.
       
   827         * @type String
       
   828         */
       
   829         DEFAULT_CSS: 'body { background-color: #fff; font: 13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small; } a, a:visited, a:hover { color: blue !important; text-decoration: underline !important; cursor: text !important; } img { cursor: pointer !important; border: none; }',
       
   830         /**
       
   831         * The template string used to create the iframe, deprecated to use DOM instead of innerHTML
       
   832         * @static
       
   833         * @property HTML
       
   834         * @type String
       
   835         * @deprecated
       
   836         */
       
   837         //HTML: '<iframe border="0" frameBorder="0" marginWidth="0" marginHeight="0" leftMargin="0" topMargin="0" allowTransparency="true" width="100%" height="99%"></iframe>',
       
   838         /**
       
   839         * Attributes to auto add to the dynamic iframe under the hood
       
   840         * @static
       
   841         * @property IFRAME_ATTRS
       
   842         * @type Object
       
   843         */
       
   844         IFRAME_ATTRS: {
       
   845             border: '0',
       
   846             frameBorder: '0',
       
   847             marginWidth: '0',
       
   848             marginHeight: '0',
       
   849             leftMargin: '0',
       
   850             topMargin: '0',
       
   851             allowTransparency: 'true',
       
   852             width: "100%",
       
   853             height: "99%"
       
   854         },
       
   855         /**
       
   856         * @static
       
   857         * @property PAGE_HTML
       
   858         * @description The template used to create the page when created dynamically.
       
   859         * @type String
       
   860         */
       
   861         PAGE_HTML: '<html dir="{DIR}" lang="{LANG}"><head><title>{TITLE}</title>{META}<base href="{BASE_HREF}"/>{LINKED_CSS}<style id="editor_css">{DEFAULT_CSS}</style>{EXTRA_CSS}</head><body>{CONTENT}</body></html>',
       
   862 
       
   863         /**
       
   864         * @static
       
   865         * @method getDocType
       
   866         * @description Parses document.doctype and generates a DocType to match the parent page, if supported.
       
   867         * For IE8, it grabs document.all[0].nodeValue and uses that. For IE < 8, it falls back to Frame.DOC_TYPE.
       
   868         * @return {String} The normalized DocType to apply to the iframe
       
   869         */
       
   870         getDocType: function() {
       
   871             var dt = Y.config.doc.doctype,
       
   872                 str = Frame.DOC_TYPE;
       
   873 
       
   874             if (dt) {
       
   875                 str = '<!DOCTYPE ' + dt.name + ((dt.publicId) ? ' ' + dt.publicId : '') + ((dt.systemId) ? ' ' + dt.systemId : '') + '>';
       
   876             } else {
       
   877                 if (Y.config.doc.all) {
       
   878                     dt = Y.config.doc.all[0];
       
   879                     if (dt.nodeType) {
       
   880                         if (dt.nodeType === 8) {
       
   881                             if (dt.nodeValue) {
       
   882                                 if (dt.nodeValue.toLowerCase().indexOf('doctype') !== -1) {
       
   883                                     str = '<!' + dt.nodeValue + '>';
       
   884                                 }
       
   885                             }
       
   886                         }
       
   887                     }
       
   888                 }
       
   889             }
       
   890             return str;
       
   891         },
       
   892         /**
       
   893         * @static
       
   894         * @property DOC_TYPE
       
   895         * @description The DOCTYPE to prepend to the new document when created. Should match the one on the page being served.
       
   896         * @type String
       
   897         */
       
   898         DOC_TYPE: '<!DOCTYPE HTML PUBLIC "-/'+'/W3C/'+'/DTD HTML 4.01/'+'/EN" "http:/'+'/www.w3.org/TR/html4/strict.dtd">',
       
   899         /**
       
   900         * @static
       
   901         * @property META
       
   902         * @description The meta-tag for Content-Type to add to the dynamic document
       
   903         * @type String
       
   904         */
       
   905         META: '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=7">',
       
   906         //META: '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>',
       
   907         /**
       
   908         * @static
       
   909         * @property NAME
       
   910         * @description The name of the class (frame)
       
   911         * @type String
       
   912         */
       
   913         NAME: 'frame',
       
   914         /**
       
   915         * The namespace on which Frame plugin will reside.
       
   916         *
       
   917         * @property NS
       
   918         * @type String
       
   919         * @default 'frame'
       
   920         * @static
       
   921         */
       
   922         NS: 'frame',
       
   923         ATTRS: {
       
   924             /**
       
   925             * @attribute title
       
   926             * @description The title to give the blank page.
       
   927             * @type String
       
   928             */
       
   929             title: {
       
   930                 value: 'Blank Page'
       
   931             },
       
   932             /**
       
   933             * @attribute dir
       
   934             * @description The default text direction for this new frame. Default: ltr
       
   935             * @type String
       
   936             */
       
   937             dir: {
       
   938                 value: 'ltr'
       
   939             },
       
   940             /**
       
   941             * @attribute lang
       
   942             * @description The default language. Default: en-US
       
   943             * @type String
       
   944             */
       
   945             lang: {
       
   946                 value: 'en-US'
       
   947             },
       
   948             /**
       
   949             * @attribute src
       
   950             * @description The src of the iframe/window. Defaults to javascript:;
       
   951             * @type String
       
   952             */
       
   953             src: {
       
   954                 //Hackish, IE needs the false in the Javascript URL
       
   955                 value: 'javascript' + ((Y.UA.ie) ? ':false' : ':') + ';'
       
   956             },
       
   957             /**
       
   958             * @attribute designMode
       
   959             * @description Should designMode be turned on after creation.
       
   960             * @writeonce
       
   961             * @type Boolean
       
   962             */
       
   963             designMode: {
       
   964                 writeOnce: true,
       
   965                 value: false
       
   966             },
       
   967             /**
       
   968             * @attribute content
       
   969             * @description The string to inject into the body of the new frame/window.
       
   970             * @type String
       
   971             */
       
   972             content: {
       
   973                 validator: Lang.isString,
       
   974                 value: '<br>',
       
   975                 setter: '_setHTML',
       
   976                 getter: '_getHTML'
       
   977             },
       
   978             /**
       
   979             * @attribute basehref
       
   980             * @description The base href to use in the iframe.
       
   981             * @type String
       
   982             */
       
   983             basehref: {
       
   984                 value: false,
       
   985                 getter: '_resolveBaseHref'
       
   986             },
       
   987             /**
       
   988             * @attribute use
       
   989             * @description Array of modules to include in the scoped YUI instance at render time. Default: ['none', 'selector-css2']
       
   990             * @writeonce
       
   991             * @type Array
       
   992             */
       
   993             use: {
       
   994                 writeOnce: true,
       
   995                 value: ['node', 'node-style', 'selector-css3']
       
   996             },
       
   997             /**
       
   998             * @attribute container
       
   999             * @description The container to append the iFrame to on render.
       
  1000             * @type String/HTMLElement/Node
       
  1001             */
       
  1002             container: {
       
  1003                 value: 'body',
       
  1004                 setter: function(n) {
       
  1005                     return Y.one(n);
       
  1006                 }
       
  1007             },
       
  1008             /**
       
  1009             * @attribute node
       
  1010             * @description The Node instance of the iframe.
       
  1011             * @type Node
       
  1012             */
       
  1013             node: {
       
  1014                 readOnly: true,
       
  1015                 value: null,
       
  1016                 getter: function() {
       
  1017                     return this._iframe;
       
  1018                 }
       
  1019             },
       
  1020             /**
       
  1021             * @attribute id
       
  1022             * @description Set the id of the new Node. (optional)
       
  1023             * @type String
       
  1024             * @writeonce
       
  1025             */
       
  1026             id: {
       
  1027                 writeOnce: true,
       
  1028                 getter: function(id) {
       
  1029                     if (!id) {
       
  1030                         id = 'iframe-' + Y.guid();
       
  1031                     }
       
  1032                     return id;
       
  1033                 }
       
  1034             },
       
  1035             /**
       
  1036             * @attribute linkedcss
       
  1037             * @description An array of url's to external linked style sheets
       
  1038             * @type String|Array
       
  1039             */
       
  1040             linkedcss: {
       
  1041                 validator: '_validateLinkedCSS',
       
  1042                 getter: '_getLinkedCSS',
       
  1043                 setter: '_setLinkedCSS'
       
  1044             },
       
  1045             /**
       
  1046             * @attribute extracss
       
  1047             * @description A string of CSS to add to the Head of the Editor
       
  1048             * @type String
       
  1049             */
       
  1050             extracss: {
       
  1051                 validator: Lang.isString,
       
  1052                 setter: '_setExtraCSS'
       
  1053             },
       
  1054             /**
       
  1055             * @attribute defaultblock
       
  1056             * @description The default tag to use for block level items, defaults to: p
       
  1057             * @type String
       
  1058             */
       
  1059             defaultblock: {
       
  1060                 value: 'p'
       
  1061             }
       
  1062         }
       
  1063     });
       
  1064 
       
  1065     Y.namespace('Plugin');
       
  1066 
       
  1067     Y.Plugin.Frame = Frame;
       
  1068 
       
  1069     Y.Frame = Frame;
       
  1070 
       
  1071 
       
  1072 
       
  1073 }, '@VERSION@', {"requires": ["base", "node", "plugin", "selector-css3", "yui-throttle"]});