最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

html - Create an embedded JavaScript in a Cross Domain Host Page which is not affected by the Host Page CSS? - Stack Overflow

programmeradmin2浏览0评论

Most javascript widget which can be embedded into a website use the following structure. First you embed a code snipped like this:

<script type="text/javascript">
window.$zopim||(function(d,s){var z=$zopim=function(c){
z._.push(c)},
$=z.s=d.createElement(s),
e=d.getElementsByTagName(s)[0];
z.set=function(o){
    z.set._.push(o)
};
z._=[];
z.set._=[];
$.async=!0;
$.setAttribute('charset','utf-8');
$.src='//v2.zopim/?2342323423434234234';
z.t=+new Date;
$.type='text/javascript';
e.parentNode.insertBefore($,e)})(document,'script');
</script>

Then, when load your page this script creates a html structure like this:

<div class="widget-class">
  <iframe src="about:blank">
    // the content of the widget
  </iframe>
</div

I see this same structure in many chat services like:

/ 
/
/

All have in common that their iframe does not have a src, i.e., an URL attached.

Update: Here is the script I use to load my widget code into a third party website:

<script type="text/javascript">
(function(d){
    var f = d.getElementsByTagName('SCRIPT')[0], p = d.createElement('SCRIPT');
    window.WidgetId = "1234";   
    p.type = 'text/javascript';
    p.setAttribute('charset','utf-8');
    p.async = true;     
    p.src = "//www.example/assets/clientwidget/chatwidget.nocache.js";     
    f.parentNode.insertBefore(p, f);
}(document));
</script>    

I want that the CSS of the site where the GWT widget is integrated should not influence the CSS of the GWT widget. I will prevent that the CSS of the host page influence the CSS of my GWT widget.

Note: I want to have access to tho host website from my GWT widget too.
The domain of the host page is www.example and the domain of the iframe is www.widget. I also want to set cookies of the host domain from the iframe.

What is the procedure of building a widget running on such a structure? How is the content of the iframe being set? Is there a pattern for that? How can I do that with GWT

Most javascript widget which can be embedded into a website use the following structure. First you embed a code snipped like this:

<script type="text/javascript">
window.$zopim||(function(d,s){var z=$zopim=function(c){
z._.push(c)},
$=z.s=d.createElement(s),
e=d.getElementsByTagName(s)[0];
z.set=function(o){
    z.set._.push(o)
};
z._=[];
z.set._=[];
$.async=!0;
$.setAttribute('charset','utf-8');
$.src='//v2.zopim.com/?2342323423434234234';
z.t=+new Date;
$.type='text/javascript';
e.parentNode.insertBefore($,e)})(document,'script');
</script>

Then, when load your page this script creates a html structure like this:

<div class="widget-class">
  <iframe src="about:blank">
    // the content of the widget
  </iframe>
</div

I see this same structure in many chat services like:

https://en.zopim.com/ 
http://banckle.com/
https://www.livechatinc.com/

All have in common that their iframe does not have a src, i.e., an URL attached.

Update: Here is the script I use to load my widget code into a third party website:

<script type="text/javascript">
(function(d){
    var f = d.getElementsByTagName('SCRIPT')[0], p = d.createElement('SCRIPT');
    window.WidgetId = "1234";   
    p.type = 'text/javascript';
    p.setAttribute('charset','utf-8');
    p.async = true;     
    p.src = "//www.example.com/assets/clientwidget/chatwidget.nocache.js";     
    f.parentNode.insertBefore(p, f);
}(document));
</script>    

I want that the CSS of the site where the GWT widget is integrated should not influence the CSS of the GWT widget. I will prevent that the CSS of the host page influence the CSS of my GWT widget.

Note: I want to have access to tho host website from my GWT widget too.
The domain of the host page is www.example.com and the domain of the iframe is www.widget.com. I also want to set cookies of the host domain from the iframe.

What is the procedure of building a widget running on such a structure? How is the content of the iframe being set? Is there a pattern for that? How can I do that with GWT

Share Improve this question edited Jan 11, 2016 at 16:22 Michael asked Jan 4, 2016 at 20:51 MichaelMichael 33.3k50 gold badges222 silver badges374 bronze badges 3
  • I'm not very good with GWT, this may help you? Embedding HTML Document in an IFRAME With GWT – Stefano Saitta Commented Jan 9, 2016 at 3:54
  • No this does not help me. – Michael Commented Jan 9, 2016 at 8:53
  • Possible duplicate of Iframe without src but still has content? – Michał Perłakowski Commented Jan 10, 2016 at 21:41
Add a comment  | 

4 Answers 4

Reset to default 6 +200

I don't know GWT, but you can easily achieve this in plain JavaScript.

Let's assume you're creating an online-count widget. At first, create an iframe:

<script id="your-widget">
  // Select the script tag used to load the widget.
  var scriptElement = document.querySelector("your-widget");
  // Create an iframe.
  var iframe = document.createElement("iframe");
  // Insert iframe before script's next sibling, i.e. after the script.
  scriptElement.parentNode.insertBefore(iframe, scriptElement.nextSibling);
  // rest of the code
</script>

Then fetch the online count using JSONP (see What is JSONP all about?), for example:

// The URL of your API, without JSONP callback parameter.
var url = "your-api-url";
// Callback function used for JSONP.
// Executed as soon as server response is received.
function callback(count) {
  // rest of code
}
// Create a script.
var script = document.createElement("script");
// Set script's src attribute to API URL + JSONP callback parameter.
// It makes browser send HTTP request to the API.
script.src = url + "?callback=callback";

Then handle server response (inside the callback() function):

// Create a div element
var div = document.createElement("div");
// Insert online count to this element.
// I assume that server response is plain-text number, for example 5.
div.innerHTML = count;
// Append div to iframe's body.
iframe.contentWindow.document.body.appendChild(div);

That's all. Your whole code could look like this:

Snippet to insert into third party website:

<script type="text/javascript">
(function(d){
    var f = d.getElementsByTagName('SCRIPT')[0], p = d.createElement('SCRIPT');
    window.WidgetId = "1234";   
    p.type = 'text/javascript';
    p.setAttribute('charset','utf-8');
    p.async = true;
    p.id = "your-widget";
    p.src = "//www.example.com/assets/clientwidget/chatwidget.nocache.js";     
    f.parentNode.insertBefore(p, f);
}(document));
</script>    

JavaScript file on your server:

// Select the script tag used to load the widget.
var scriptElement = document.querySelector("#your-widget");
// Create an iframe.
var iframe = document.createElement("iframe");
// Insert iframe before script's next sibling, i.e. after the script.
scriptElement.parentNode.insertBefore(iframe, scriptElement.nextSibling);

// The URL of your API, without JSONP callback parameter.
var url = "your-api-url";
// Callback function used for JSONP.
// Executed as soon as server response is received.
function callback(count) {
  // Create a div element
  var div = document.createElement("div");
  // Insert online count to this element.
  // I assume that server response is plain-text number, for example 5.
  div.innerHTML = count;
  // Append div to iframe's body.
  iframe.contentWindow.document.body.appendChild(div);
}
// Create a script.
var script = document.createElement("script");
// Set script's src attribute to API URL + JSONP callback parameter.
// It makes browser send HTTP request to the API.
script.src = url + "?callback=callback";

EDIT:
if you want your widget to not be influenced by any css from the "outside" you have to load into an iframe.

code to add to your website to load any gwt project/widget:

<iframe id="1234" src="//www.example.com/assets/Chatwidget.html" style="border: 1px solid black;" tabindex="-1"></iframe>

notice: that im NOT loading the nocache.js but the yourwidget.html file. like this all your clases insde the frame wont be affected by any class from the outside.

to access anything outside ofthis iframe you can use jsni methods. this will only work if the domain of your iframe and the thirdpartysite are the same. otherwise youve to use window.postMessage:

public native static void yourMethod() /*-{
     $wnd.parent.someMethodFromOutsideTheIframe(); 
}-*/;

EDIT2:

by using the snippet from above you make sure that your widget is not influened by any css from the hostpage. to get the hostpage url from inside the widget simply add this function:

private native static String getHostPageUrl() /*-{
    return $wnd.parent.location.hostname;
}-*/;

EDIT3:

since you are on 2 different domains, you have to use window.postMessage. here one little example to get you going:

besides the iframe you have to add a event listener to the window of your example.com, that listens for the messages from your iframe. you also check if the messages comes form the correct origin.

<script>
    // Create IE + others compatible event handler
    var eventMethod = window.addEventListener ? "addEventListener"
            : "attachEvent";
    var eventer = window[eventMethod];
    var messageEvent = eventMethod == "attachEvent" ? "onmessage"
            : "message";

    // Listen to message from child window
    eventer(messageEvent, function(e) {
        //check for the correct origin, if wanted
        //if ( e.origin !== "http://www.widget.com" )
        //        return
        console.log('parent received message!:  ', e.data);
        //here you can set your cookie
        document.cookie = 'cookie=widget; expires=Fri, 1 Feb 2016 18:00:00 UTC; path=/'
    }, false);
</script>

From inside your widget you call this method:

public native static void postMessageToParent(String message) /*-{
    //message to sent, the host that is supposed to receive it
    $wnd.parent.postMessage(message, "http://www.example.com");
}-*/;

i put a working example on pastebin:

javascript to insert into your page: http://pastebin.com/Y0iDTntw
gwt class with onmoduleload: http://pastebin.com/QjDRuPmg

Here's a full functional simple widget expample project I wrote in cloud9 (online IDE) with javascript, please feel free to request an access if you want to edit it, viewing is publicly available (for registered users - registration is free).

sources: https://ide.c9.io/nmlc/widget-example, result: https://widget-example-nmlc.c9users.io/index.html

As for the question about how do they do it:

It seems that zopim builds their widgets gradually on the client side, defining and requiring basic modules (like these __$$__meshim_widget_components_mobileChatWindow_MainScreen), which are consist from submodules and then process everything with __$$__jx_ui_HTMLElement builder which creates HTML elements and appends them to provided parent nodes. All that compiles to the resulting HTML of the chatbox. Btw, judging by the names of some components, it seems, they build their widgets with some "meshim" library, but I have never heard of this library.

this.dom.src='about:blank'
this.appendToParent(!0)
var H=this.iwin=this.dom.contentWindow
var I=this.idoc=r.extend(H.document)
I.write(G)
I.close()

This, I guess, is the place where zopim service creates an iframe for their widgets. I'm not sure why they are using document.write instead of appendChild (document.write drops event bindings), but I have implemented both versions - they are pretty much the same except setIframeContents and addHtmlElement functions.

Hope someone will find this useful :).

1) There are many different ways to load content to iframe. Iframe have isolated content. iframe that you put in host page, does not have src, because of browser secure politic, you can't simply load content from other domains. But you can load js from other domain.For this porpuse you need usw JSONP

2) to share cookies with host page and widget iframe, you need use postMessage api like in this post

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论