1 // Copyright 2014 The Cloud Input Tools Authors. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
16 * @fileoverview Provides common operation of dom for input tools.
20 goog
.provide('i18n.input.common.dom');
22 goog
.require('goog.array');
23 goog
.require('goog.dom');
24 goog
.require('goog.dom.TagName');
25 goog
.require('goog.dom.classlist');
26 goog
.require('goog.style');
27 goog
.require('goog.uri.utils');
28 goog
.require('i18n.input.common.GlobalSettings');
32 * When detects whether the same domain iframe, browser will throw
33 * exceptions on accessing the cross domain iframe. Stores result to avoid to
34 * throws exception twice.
35 * Key is document uid, value is object. ifrmae uid : true/false
37 * @type {!Object.<number, !Object.<number, boolean>>}
40 i18n
.input
.common
.dom
.sameDomainIframes_
= {};
44 * Checks the given element whether is editable.
46 * @param {!Element} element The element.
47 * @return {boolean} Whether the give element is editable.
49 i18n
.input
.common
.dom
.isEditable = function(element
) {
50 if (!element
.tagName
) {
54 if (element
.readOnly
) {
58 switch (element
.tagName
.toUpperCase()) {
62 return (element
.type
.toUpperCase() == 'TEXT' ||
63 element
.type
.toUpperCase() == 'SEARCH');
65 return element
.isContentEditable
;
67 // Accessing iframe's contents or properties throws exception when the
68 // iframe is not hosted on the same domain.
69 // When it happens, ignore it and consider this iframe isn't editable.
72 var ifdoc
= i18n
.input
.common
.dom
.getSameDomainFrameDoc(element
);
73 return !!ifdoc
&& (ifdoc
.designMode
&&
74 ifdoc
.designMode
.toUpperCase() == 'ON' ||
75 ifdoc
.body
&& ifdoc
.body
.isContentEditable
);
86 * Sets class names to an element.
88 * @param {Element} elem Element to set class names.
89 * @param {Array.<string>} classes Class names.
91 i18n
.input
.common
.dom
.setClasses = function(elem
, classes
) {
93 for (var i
= 0; i
< classes
.length
; i
++) {
95 goog
.dom
.classlist
.set(elem
, classes
[0]);
97 goog
.dom
.classlist
.add(elem
, classes
[i
]);
105 * Check the iframe whether is the same domain as the current domain.
106 * Returns the iframe content document when it's the same domain,
107 * otherwise return null.
109 * @param {!Element} element The iframe element.
110 * @return {Document} The iframe content document.
112 i18n
.input
.common
.dom
.getSameDomainFrameDoc = function(element
) {
113 var uid
= goog
.getUid(document
);
114 var frameUid
= goog
.getUid(element
);
115 var states
= i18n
.input
.common
.dom
.sameDomainIframes_
[uid
];
117 states
= i18n
.input
.common
.dom
.sameDomainIframes_
[uid
] = {};
121 var url
= window
.location
.href
|| '';
122 //Note: cross-domain IFRAME's src can be:
126 // Non-cross-domain IFRAME's src can be:
133 if (!(frameUid
in states
)) {
135 var pos
= element
.src
.indexOf('//');
136 var protocol
= pos
< 0 ? 'N/A' : element
.src
.slice(0, pos
);
137 states
[frameUid
] = (protocol
!= '' &&
138 protocol
!= 'http:' &&
139 protocol
!= 'https:' ||
140 goog
.uri
.utils
.haveSameDomain(element
.src
, url
));
142 states
[frameUid
] = true;
145 return states
[frameUid
] ? goog
.dom
.getFrameContentDocument(element
) : null;
147 states
[frameUid
] = false;
154 * Gets the same domain iframe or frame document in given document, default
155 * given document is current document.
157 * @param {Document=} opt_doc The given document.
158 * @return {Array.<!Document>} The same domain iframe document.
160 i18n
.input
.common
.dom
.getSameDomainDocuments = function(opt_doc
) {
161 var doc
= opt_doc
|| document
;
164 goog
.array
.extend(iframes
,
165 doc
.getElementsByTagName(goog
.dom
.TagName
.IFRAME
),
166 doc
.getElementsByTagName(goog
.dom
.TagName
.FRAME
));
167 goog
.array
.forEach(iframes
, function(frame
) {
168 var frameDoc
= i18n
.input
.common
.dom
.getSameDomainFrameDoc(frame
);
169 frameDoc
&& rets
.push(frameDoc
);
176 * Create the iframe in given document or default document. Then the input tool
177 * UI element will be create inside the iframe document to avoid CSS conflict.
179 * @param {Document=} opt_doc The given document.
180 * @return {!Element} The iframe element.
182 i18n
.input
.common
.dom
.createIframeWrapper = function(opt_doc
) {
183 var doc
= opt_doc
|| document
;
184 var dom
= goog
.dom
.getDomHelper();
185 var frame
= dom
.createDom(goog
.dom
.TagName
.IFRAME
, {
188 'style': 'background-color:transparent;border:0;display:none;'
190 dom
.append(/** @type {!Element} */ (doc
.body
), frame
);
191 var frameDoc
= dom
.getFrameContentDocument(frame
);
193 var css
= i18n
.input
.common
.GlobalSettings
.alternativeImageUrl
?
194 i18n
.input
.common
.GlobalSettings
.css
.replace(
195 /\/\/ssl.gstatic.com\/inputtools\/images/g,
196 i18n
.input
.common
.GlobalSettings
.alternativeImageUrl
) :
197 i18n
.input
.common
.GlobalSettings
.css
;
198 goog
.style
.installStyles(
199 'html body{border:0;margin:0;padding:0} html,body{overflow:hidden}' +
200 css
, /** @type {!Element} */(frameDoc
.body
));
206 * The property need to be copied from original element to its iframe wrapper.
208 * @type {!Array.<string>}
211 i18n
.input
.common
.dom
.iframeWrapperProperty_
= ['box-shadow', 'z-index',
212 'margin', 'position', 'display'];
216 * Copies the necessary properties value from original element to its iframe
219 * @param {Element} element .
220 * @param {Element} iframe The iframe wrapper element.
222 i18n
.input
.common
.dom
.copyNecessaryStyle = function(element
, iframe
) {
223 goog
.style
.setContentBoxSize(iframe
, goog
.style
.getSize(element
));
224 goog
.array
.forEach(i18n
.input
.common
.dom
.iframeWrapperProperty_
,
226 goog
.style
.setStyle(iframe
, property
,
227 goog
.style
.getComputedStyle(element
, property
));