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