Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

frame.js 34KB

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