Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/editor/seamlessfield.js
2868 views
1
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Class to encapsulate an editable field that blends in with
17
* the style of the page. The field can be fixed height, grow with its
18
* contents, or have a min height after which it grows to its contents.
19
* This is a goog.editor.Field, but with blending and sizing capabilities,
20
* and avoids using an iframe whenever possible.
21
*
22
* @author [email protected] (Nick Santos)
23
* @see ../demos/editor/seamlessfield.html
24
*/
25
26
27
goog.provide('goog.editor.SeamlessField');
28
29
goog.require('goog.cssom.iframe.style');
30
goog.require('goog.dom');
31
goog.require('goog.dom.Range');
32
goog.require('goog.dom.TagName');
33
goog.require('goog.dom.safe');
34
goog.require('goog.editor.BrowserFeature');
35
goog.require('goog.editor.Field');
36
goog.require('goog.editor.icontent');
37
goog.require('goog.editor.icontent.FieldFormatInfo');
38
goog.require('goog.editor.icontent.FieldStyleInfo');
39
goog.require('goog.editor.node');
40
goog.require('goog.events');
41
goog.require('goog.events.EventType');
42
goog.require('goog.html.legacyconversions');
43
goog.require('goog.html.uncheckedconversions');
44
goog.require('goog.log');
45
goog.require('goog.string.Const');
46
goog.require('goog.style');
47
48
49
50
/**
51
* This class encapsulates an editable field that blends in with the
52
* surrounding page.
53
* To see events fired by this object, please see the base class.
54
*
55
* @param {string} id An identifer for the field. This is used to find the
56
* field and the element associated with this field.
57
* @param {Document=} opt_doc The document that the element with the given
58
* id can be found it.
59
* @constructor
60
* @extends {goog.editor.Field}
61
*/
62
goog.editor.SeamlessField = function(id, opt_doc) {
63
goog.editor.Field.call(this, id, opt_doc);
64
};
65
goog.inherits(goog.editor.SeamlessField, goog.editor.Field);
66
67
68
/**
69
* @override
70
*/
71
goog.editor.SeamlessField.prototype.logger =
72
goog.log.getLogger('goog.editor.SeamlessField');
73
74
// Functions dealing with field sizing.
75
76
77
/**
78
* The key used for listening for the "dragover" event.
79
* @type {goog.events.Key}
80
* @private
81
*/
82
goog.editor.SeamlessField.prototype.listenForDragOverEventKey_;
83
84
85
/**
86
* The key used for listening for the iframe "load" event.
87
* @type {goog.events.Key}
88
* @private
89
*/
90
goog.editor.SeamlessField.prototype.listenForIframeLoadEventKey_;
91
92
93
/**
94
* Sets the min height of this editable field's iframe. Only used in growing
95
* mode when an iframe is used. This will cause an immediate field sizing to
96
* update the field if necessary based on the new min height.
97
* @param {number} height The min height specified as a number of pixels,
98
* e.g., 75.
99
*/
100
goog.editor.SeamlessField.prototype.setMinHeight = function(height) {
101
if (height == this.minHeight_) {
102
// Do nothing if the min height isn't changing.
103
return;
104
}
105
this.minHeight_ = height;
106
if (this.usesIframe()) {
107
this.doFieldSizingGecko();
108
}
109
};
110
111
112
/**
113
* Whether the field should be rendered with a fixed height, or should expand
114
* to fit its contents.
115
* @type {boolean}
116
* @private
117
*/
118
goog.editor.SeamlessField.prototype.isFixedHeight_ = false;
119
120
121
/**
122
* Whether the fixed-height handling has been overridden manually.
123
* @type {boolean}
124
* @private
125
*/
126
goog.editor.SeamlessField.prototype.isFixedHeightOverridden_ = false;
127
128
129
/**
130
* @return {boolean} Whether the field should be rendered with a fixed
131
* height, or should expand to fit its contents.
132
* @override
133
*/
134
goog.editor.SeamlessField.prototype.isFixedHeight = function() {
135
return this.isFixedHeight_;
136
};
137
138
139
/**
140
* @param {boolean} newVal Explicitly set whether the field should be
141
* of a fixed-height. This overrides auto-detection.
142
*/
143
goog.editor.SeamlessField.prototype.overrideFixedHeight = function(newVal) {
144
this.isFixedHeight_ = newVal;
145
this.isFixedHeightOverridden_ = true;
146
};
147
148
149
/**
150
* Auto-detect whether the current field should have a fixed height.
151
* @private
152
*/
153
goog.editor.SeamlessField.prototype.autoDetectFixedHeight_ = function() {
154
if (!this.isFixedHeightOverridden_) {
155
var originalElement = this.getOriginalElement();
156
if (originalElement) {
157
this.isFixedHeight_ =
158
goog.style.getComputedOverflowY(originalElement) == 'auto';
159
}
160
}
161
};
162
163
164
/**
165
* Resize the iframe in response to the wrapper div changing size.
166
* @private
167
*/
168
goog.editor.SeamlessField.prototype.handleOuterDocChange_ = function() {
169
if (this.isEventStopped(goog.editor.Field.EventType.CHANGE)) {
170
return;
171
}
172
this.sizeIframeToWrapperGecko_();
173
};
174
175
176
/**
177
* Sizes the iframe to its body's height.
178
* @private
179
*/
180
goog.editor.SeamlessField.prototype.sizeIframeToBodyHeightGecko_ = function() {
181
if (this.acquireSizeIframeLockGecko_()) {
182
var resized = false;
183
var ifr = this.getEditableIframe();
184
if (ifr) {
185
var fieldHeight = this.getIframeBodyHeightGecko_();
186
187
if (this.minHeight_) {
188
fieldHeight = Math.max(fieldHeight, this.minHeight_);
189
}
190
if (parseInt(goog.style.getStyle(ifr, 'height'), 10) != fieldHeight) {
191
ifr.style.height = fieldHeight + 'px';
192
resized = true;
193
}
194
}
195
this.releaseSizeIframeLockGecko_();
196
if (resized) {
197
this.dispatchEvent(goog.editor.Field.EventType.IFRAME_RESIZED);
198
}
199
}
200
};
201
202
203
/**
204
* @return {number} The height of the editable iframe's body.
205
* @private
206
*/
207
goog.editor.SeamlessField.prototype.getIframeBodyHeightGecko_ = function() {
208
var ifr = this.getEditableIframe();
209
var body = ifr.contentDocument.body;
210
var htmlElement = /** @type {!HTMLElement} */ (body.parentNode);
211
212
213
// If the iframe's height is 0, then the offsetHeight/scrollHeight of the
214
// HTML element in the iframe can be totally wack (i.e. too large
215
// by 50-500px). Also, in standard's mode the clientHeight is 0.
216
if (parseInt(goog.style.getStyle(ifr, 'height'), 10) === 0) {
217
goog.style.setStyle(ifr, 'height', 1 + 'px');
218
}
219
220
var fieldHeight;
221
if (goog.editor.node.isStandardsMode(body)) {
222
// If in standards-mode,
223
// grab the HTML element as it will contain all the field's
224
// contents. The body's height, for example, will not include that of
225
// floated images at the bottom in standards mode.
226
// Note that this value include all scrollbars *except* for scrollbars
227
// on the HTML element itself.
228
fieldHeight = htmlElement.offsetHeight;
229
} else {
230
// In quirks-mode, the body-element always seems
231
// to size to the containing window. The html-element however,
232
// sizes to the content, and can thus end up with a value smaller
233
// than its child body-element if the content is shrinking.
234
// We want to make the iframe shrink too when the content shrinks,
235
// so rather than size the iframe to the body-element, size it to
236
// the html-element.
237
fieldHeight = htmlElement.scrollHeight;
238
239
// If there is a horizontal scroll, add in the thickness of the
240
// scrollbar.
241
if (htmlElement.clientHeight != htmlElement.offsetHeight) {
242
fieldHeight += goog.editor.SeamlessField.getScrollbarWidth_();
243
}
244
}
245
246
return fieldHeight;
247
};
248
249
250
/**
251
* Grabs the width of a scrollbar from the browser and caches the result.
252
* @return {number} The scrollbar width in pixels.
253
* @private
254
*/
255
goog.editor.SeamlessField.getScrollbarWidth_ = function() {
256
return goog.editor.SeamlessField.scrollbarWidth_ ||
257
(goog.editor.SeamlessField.scrollbarWidth_ =
258
goog.style.getScrollbarWidth());
259
};
260
261
262
/**
263
* Sizes the iframe to its container div's width. The width of the div
264
* is controlled by its containing context, not by its contents.
265
* if it extends outside of it's contents, then it gets a horizontal scroll.
266
* @private
267
*/
268
goog.editor.SeamlessField.prototype.sizeIframeToWrapperGecko_ = function() {
269
if (this.acquireSizeIframeLockGecko_()) {
270
var ifr = this.getEditableIframe();
271
var field = this.getElement();
272
var resized = false;
273
if (ifr && field) {
274
var fieldPaddingBox;
275
var widthDiv = /** @type {!HTMLElement} */ (ifr.parentNode);
276
277
var width = widthDiv.offsetWidth;
278
if (parseInt(goog.style.getStyle(ifr, 'width'), 10) != width) {
279
fieldPaddingBox = goog.style.getPaddingBox(field);
280
ifr.style.width = width + 'px';
281
field.style.width =
282
width - fieldPaddingBox.left - fieldPaddingBox.right + 'px';
283
resized = true;
284
}
285
286
var height = widthDiv.offsetHeight;
287
if (this.isFixedHeight() &&
288
parseInt(goog.style.getStyle(ifr, 'height'), 10) != height) {
289
if (!fieldPaddingBox) {
290
fieldPaddingBox = goog.style.getPaddingBox(field);
291
}
292
ifr.style.height = height + 'px';
293
field.style.height =
294
height - fieldPaddingBox.top - fieldPaddingBox.bottom + 'px';
295
resized = true;
296
}
297
}
298
this.releaseSizeIframeLockGecko_();
299
if (resized) {
300
this.dispatchEvent(goog.editor.Field.EventType.IFRAME_RESIZED);
301
}
302
}
303
};
304
305
306
/**
307
* Perform all the sizing immediately.
308
*/
309
goog.editor.SeamlessField.prototype.doFieldSizingGecko = function() {
310
// Because doFieldSizingGecko can be called after a setTimeout
311
// it is possible that the field has been destroyed before this call
312
// to do the sizing is executed. Check for field existence and do nothing
313
// if it has already been destroyed.
314
if (this.getElement()) {
315
// The order of operations is important here. Sizing the iframe to the
316
// wrapper could cause the width to change, which could change the line
317
// wrapping, which could change the body height. So we need to do that
318
// first, then size the iframe to fit the body height.
319
this.sizeIframeToWrapperGecko_();
320
if (!this.isFixedHeight()) {
321
this.sizeIframeToBodyHeightGecko_();
322
}
323
}
324
};
325
326
327
/**
328
* Acquires a lock on resizing the field iframe. This is used to ensure that
329
* modifications we make while in a mutation event handler don't cause
330
* infinite loops.
331
* @return {boolean} False if the lock is already acquired.
332
* @private
333
*/
334
goog.editor.SeamlessField.prototype.acquireSizeIframeLockGecko_ = function() {
335
if (this.sizeIframeLock_) {
336
return false;
337
}
338
return this.sizeIframeLock_ = true;
339
};
340
341
342
/**
343
* Releases a lock on resizing the field iframe. This is used to ensure that
344
* modifications we make while in a mutation event handler don't cause
345
* infinite loops.
346
* @private
347
*/
348
goog.editor.SeamlessField.prototype.releaseSizeIframeLockGecko_ = function() {
349
this.sizeIframeLock_ = false;
350
};
351
352
353
// Functions dealing with blending in with the surrounding page.
354
355
356
/**
357
* String containing the css rules that, if applied to a document's body,
358
* would style that body as if it were the original element we made editable.
359
* See goog.cssom.iframe.style.getElementContext for more details.
360
* @type {string}
361
* @private
362
*/
363
goog.editor.SeamlessField.prototype.iframeableCss_ = '';
364
365
366
/**
367
* Gets the css rules that should be used to style an iframe's body as if it
368
* were the original element that we made editable.
369
* @param {boolean=} opt_forceRegeneration Set to true to not read the cached
370
* copy and instead completely regenerate the css rules.
371
* @return {string} The string containing the css rules to use.
372
*/
373
goog.editor.SeamlessField.prototype.getIframeableCss = function(
374
opt_forceRegeneration) {
375
if (!this.iframeableCss_ || opt_forceRegeneration) {
376
var originalElement = this.getOriginalElement();
377
if (originalElement) {
378
this.iframeableCss_ = goog.cssom.iframe.style.getElementContext(
379
originalElement, opt_forceRegeneration);
380
}
381
}
382
return this.iframeableCss_;
383
};
384
385
386
/**
387
* Sets the css rules that should be used inside the editable iframe.
388
* Note: to clear the css cache between makeNotEditable/makeEditable,
389
* call this with "" as iframeableCss.
390
* TODO(user): Unify all these css setting methods + Nick's open
391
* CL. This is getting ridiculous.
392
* @param {string} iframeableCss String containing the css rules to use.
393
*/
394
goog.editor.SeamlessField.prototype.setIframeableCss = function(iframeableCss) {
395
this.iframeableCss_ = iframeableCss;
396
};
397
398
399
/**
400
* Used to ensure that CSS stylings are only installed once for none
401
* iframe seamless mode.
402
* TODO(user): Make it a formal part of the API that you can only
403
* set one set of styles globally.
404
* In seamless, non-iframe mode, all the stylings would go in the
405
* same document and conflict.
406
* @type {boolean}
407
* @private
408
*/
409
goog.editor.SeamlessField.haveInstalledCss_ = false;
410
411
412
/**
413
* Applies CSS from the wrapper-div to the field iframe.
414
*/
415
goog.editor.SeamlessField.prototype.inheritBlendedCSS = function() {
416
// No-op if the field isn't using an iframe.
417
if (!this.usesIframe()) {
418
return;
419
}
420
var field = this.getElement();
421
var head = goog.dom.getDomHelper(field).getElementsByTagNameAndClass(
422
goog.dom.TagName.HEAD)[0];
423
if (head) {
424
// We created this <head>, and we know the only thing we put in there
425
// is a <style> block. So it's safe to blow away all the children
426
// as part of rewriting the styles.
427
goog.dom.removeChildren(head);
428
}
429
430
// Force a cache-clearing in CssUtil - this function was called because
431
// we're applying the 'blend' for the first time, or because we
432
// *need* to recompute the blend.
433
var newCSS = this.getIframeableCss(true);
434
goog.style.installSafeStyleSheet(
435
goog.html.legacyconversions.safeStyleSheetFromString(newCSS), field);
436
};
437
438
439
// Overridden methods.
440
441
442
/** @override */
443
goog.editor.SeamlessField.prototype.usesIframe = function() {
444
// TODO(user): Switch Firefox to using contentEditable
445
// rather than designMode iframe once contentEditable support
446
// is less buggy.
447
return !goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE;
448
};
449
450
451
/** @override */
452
goog.editor.SeamlessField.prototype.setupMutationEventHandlersGecko =
453
function() {
454
goog.editor.SeamlessField.superClass_.setupMutationEventHandlersGecko.call(
455
this);
456
457
if (this.usesIframe()) {
458
var iframe = this.getEditableIframe();
459
var outerDoc = iframe.ownerDocument;
460
this.eventRegister.listen(
461
outerDoc, goog.editor.Field.MUTATION_EVENTS_GECKO,
462
this.handleOuterDocChange_, true);
463
464
// If the images load after we do the initial sizing, then this will
465
// force a field resize.
466
this.listenForIframeLoadEventKey_ = goog.events.listenOnce(
467
this.getEditableDomHelper().getWindow(), goog.events.EventType.LOAD,
468
this.sizeIframeToBodyHeightGecko_, true, this);
469
470
this.eventRegister.listen(
471
outerDoc, 'DOMAttrModified',
472
goog.bind(this.handleDomAttrChange, this, this.handleOuterDocChange_),
473
true);
474
}
475
};
476
477
478
/** @override */
479
goog.editor.SeamlessField.prototype.handleChange = function() {
480
if (this.isEventStopped(goog.editor.Field.EventType.CHANGE)) {
481
return;
482
}
483
484
goog.editor.SeamlessField.superClass_.handleChange.call(this);
485
486
if (this.usesIframe()) {
487
this.sizeIframeToBodyHeightGecko_();
488
}
489
};
490
491
492
/** @override */
493
goog.editor.SeamlessField.prototype.dispatchBlur = function() {
494
if (this.isEventStopped(goog.editor.Field.EventType.BLUR)) {
495
return;
496
}
497
498
goog.editor.SeamlessField.superClass_.dispatchBlur.call(this);
499
500
// Clear the selection and restore the current range back after collapsing
501
// it. The ideal solution would have been to just leave the range intact; but
502
// when there are multiple fields present on the page, its important that
503
// the selection isn't retained when we switch between the fields. We also
504
// have to make sure that the cursor position is retained when we tab in and
505
// out of a field and our approach addresses both these issues.
506
// Another point to note is that we do it on a setTimeout to allow for
507
// DOM modifications on blur. Otherwise, something like setLoremIpsum will
508
// leave a blinking cursor in the field even though it's blurred.
509
if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE &&
510
!goog.editor.BrowserFeature.CLEARS_SELECTION_WHEN_FOCUS_LEAVES) {
511
var win = this.getEditableDomHelper().getWindow();
512
var dragging = false;
513
goog.events.unlistenByKey(this.listenForDragOverEventKey_);
514
this.listenForDragOverEventKey_ = goog.events.listenOnce(
515
win.document.body, 'dragover', function() { dragging = true; });
516
goog.global.setTimeout(goog.bind(function() {
517
// Do not clear the selection if we're only dragging text.
518
// This addresses a bug on FF1.5/linux where dragging fires a blur,
519
// but clearing the selection confuses Firefox's drag-and-drop
520
// implementation. For more info, see http://b/1061064
521
if (!dragging) {
522
if (this.editableDomHelper) {
523
var rng = this.getRange();
524
525
// If there are multiple fields on a page, we need to make sure that
526
// the selection isn't retained when we switch between fields. We
527
// could have collapsed the range but there is a bug in GECKO where
528
// the selection stays highlighted even though its backing range is
529
// collapsed (http://b/1390115). To get around this, we clear the
530
// selection and restore the collapsed range back in. Restoring the
531
// range is important so that the cursor stays intact when we tab out
532
// and into a field (See http://b/1790301 for additional details on
533
// this).
534
var iframeWindow = this.editableDomHelper.getWindow();
535
goog.dom.Range.clearSelection(iframeWindow);
536
537
if (rng) {
538
rng.collapse(true);
539
rng.select();
540
}
541
}
542
}
543
}, this), 0);
544
}
545
};
546
547
548
/** @override */
549
goog.editor.SeamlessField.prototype.turnOnDesignModeGecko = function() {
550
goog.editor.SeamlessField.superClass_.turnOnDesignModeGecko.call(this);
551
var doc = this.getEditableDomHelper().getDocument();
552
553
doc.execCommand('enableInlineTableEditing', false, 'false');
554
doc.execCommand('enableObjectResizing', false, 'false');
555
};
556
557
558
/** @override */
559
goog.editor.SeamlessField.prototype.installStyles = function() {
560
if (!this.usesIframe()) {
561
if (!goog.editor.SeamlessField.haveInstalledCss_) {
562
if (this.cssStyles) {
563
goog.style.installSafeStyleSheet(
564
goog.html.legacyconversions.safeStyleSheetFromString(
565
this.cssStyles),
566
this.getElement());
567
}
568
569
// TODO(user): this should be reset to false when the editor is quit.
570
// In non-iframe mode, CSS styles should only be instaled once.
571
goog.editor.SeamlessField.haveInstalledCss_ = true;
572
}
573
}
574
};
575
576
577
/** @override */
578
goog.editor.SeamlessField.prototype.makeEditableInternal = function(
579
opt_iframeSrc) {
580
if (this.usesIframe()) {
581
goog.editor.SeamlessField.superClass_.makeEditableInternal.call(
582
this, opt_iframeSrc);
583
} else {
584
var field = this.getOriginalElement();
585
if (field) {
586
this.setupFieldObject(field);
587
field.contentEditable = true;
588
589
this.injectContents(field.innerHTML, field);
590
591
this.handleFieldLoad();
592
}
593
}
594
};
595
596
597
/** @override */
598
goog.editor.SeamlessField.prototype.handleFieldLoad = function() {
599
if (this.usesIframe()) {
600
// If the CSS inheriting code screws up (e.g. makes fonts too large) and
601
// the field is sized off in goog.editor.Field.makeIframeField, then we need
602
// to size it correctly, but it needs to be visible for the browser
603
// to have fully rendered it. We need to put this on a timeout to give
604
// the browser time to render.
605
var self = this;
606
goog.global.setTimeout(function() { self.doFieldSizingGecko(); }, 0);
607
}
608
goog.editor.SeamlessField.superClass_.handleFieldLoad.call(this);
609
};
610
611
612
/** @override */
613
goog.editor.SeamlessField.prototype.getIframeAttributes = function() {
614
return {'frameBorder': 0, 'style': 'padding:0;'};
615
};
616
617
618
/** @override */
619
goog.editor.SeamlessField.prototype.attachIframe = function(iframe) {
620
this.autoDetectFixedHeight_();
621
var field = this.getOriginalElement();
622
var dh = goog.dom.getDomHelper(field);
623
624
// Grab the width/height values of the field before modifying any CSS
625
// as some of the modifications affect its size (e.g. innerHTML='')
626
// Here, we set the size of the field to fixed so there's not too much
627
// jiggling when we set the innerHTML of the field.
628
var oldWidth = field.style.width;
629
var oldHeight = field.style.height;
630
goog.style.setStyle(field, 'visibility', 'hidden');
631
632
// If there is a floated element at the bottom of the field,
633
// then it needs a clearing div at the end to cause the clientHeight
634
// to contain the entire field.
635
// Also, with css re-writing, the margins of the first/last
636
// paragraph don't seem to get included in the clientHeight. Specifically,
637
// the extra divs below force the field's clientHeight to include the
638
// margins on the first and last elements contained within it.
639
var startDiv = dh.createDom(
640
goog.dom.TagName.DIV,
641
{'style': 'height:0;clear:both', 'innerHTML': '&nbsp;'});
642
var endDiv = startDiv.cloneNode(true);
643
field.insertBefore(startDiv, field.firstChild);
644
goog.dom.appendChild(field, endDiv);
645
646
var contentBox = goog.style.getContentBoxSize(field);
647
var width = contentBox.width;
648
var height = contentBox.height;
649
650
var html = '';
651
if (this.isFixedHeight()) {
652
html = '&nbsp;';
653
654
goog.style.setStyle(field, 'position', 'relative');
655
goog.style.setStyle(field, 'overflow', 'visible');
656
657
goog.style.setStyle(iframe, 'position', 'absolute');
658
goog.style.setStyle(iframe, 'top', '0');
659
goog.style.setStyle(iframe, 'left', '0');
660
}
661
goog.style.setSize(field, width, height);
662
663
// In strict mode, browsers put blank space at the bottom and right
664
// if a field when it has an iframe child, to fill up the remaining line
665
// height. So make the line height = 0.
666
if (goog.editor.node.isStandardsMode(field)) {
667
this.originalFieldLineHeight_ = field.style.lineHeight;
668
goog.style.setStyle(field, 'lineHeight', '0');
669
}
670
671
goog.editor.node.replaceInnerHtml(field, html);
672
// Set the initial size
673
goog.style.setSize(iframe, width, height);
674
goog.style.setSize(field, oldWidth, oldHeight);
675
goog.style.setStyle(field, 'visibility', '');
676
goog.dom.appendChild(field, iframe);
677
678
// Only write if its not IE HTTPS in which case we're waiting for load.
679
if (!this.shouldLoadAsynchronously()) {
680
var doc = iframe.contentWindow.document;
681
if (goog.editor.node.isStandardsMode(iframe.ownerDocument)) {
682
doc.open();
683
var emptyHtml =
684
goog.html.uncheckedconversions
685
.safeHtmlFromStringKnownToSatisfyTypeContract(
686
goog.string.Const.from('HTML from constant string'),
687
'<!DOCTYPE HTML><html></html>');
688
goog.dom.safe.documentWrite(doc, emptyHtml);
689
doc.close();
690
}
691
}
692
};
693
694
695
/** @override */
696
goog.editor.SeamlessField.prototype.getFieldFormatInfo = function(extraStyles) {
697
var originalElement = this.getOriginalElement();
698
if (originalElement) {
699
return new goog.editor.icontent.FieldFormatInfo(
700
this.id, goog.editor.node.isStandardsMode(originalElement), true,
701
this.isFixedHeight(), extraStyles);
702
}
703
throw Error('no field');
704
};
705
706
707
/** @override */
708
goog.editor.SeamlessField.prototype.writeIframeContent = function(
709
iframe, innerHtml, extraStyles) {
710
// For seamless iframes, hide the iframe while we're laying it out to
711
// prevent the flicker.
712
goog.style.setStyle(iframe, 'visibility', 'hidden');
713
var formatInfo = this.getFieldFormatInfo(extraStyles);
714
var styleInfo = new goog.editor.icontent.FieldStyleInfo(
715
this.getOriginalElement(), this.cssStyles + this.getIframeableCss());
716
goog.editor.icontent.writeNormalInitialBlendedIframe(
717
formatInfo, innerHtml, styleInfo, iframe);
718
this.doFieldSizingGecko();
719
goog.style.setStyle(iframe, 'visibility', 'visible');
720
};
721
722
723
/** @override */
724
goog.editor.SeamlessField.prototype.restoreDom = function() {
725
// TODO(user): Consider only removing the iframe if we are
726
// restoring the original node.
727
if (this.usesIframe()) {
728
goog.dom.removeNode(this.getEditableIframe());
729
}
730
};
731
732
733
/** @override */
734
goog.editor.SeamlessField.prototype.clearListeners = function() {
735
goog.events.unlistenByKey(this.listenForDragOverEventKey_);
736
goog.events.unlistenByKey(this.listenForIframeLoadEventKey_);
737
738
goog.editor.SeamlessField.base(this, 'clearListeners');
739
};
740
741