Building Widgets and APIs using: Third Party JavaScript
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Bjørnstad, Torstein
When building a web page composed of different parts, the different parts can be combined at different stages of page rendering. Everything can either be loaded on the server before being returned to the client, or the client might receive the minimum amount of data immediately before loading individual components using JavaScript. The first way might be more straight-forward, but the latter both allows for looser coupling between services as well as allowing better user interation with the various page components. There are many scenarios where third-party JavaScript provides a good separation of concerns. You might be building a site with several secondary features like comment fields, feedback dialogs or shared toolbars, or you might be providing widgets or an API for other websites to consume. All of these cases are good candidates for writing so-called third-party JavaScript applications. When writing JavaScript that should run on known or unknown sites there are a lot of considerations to take into account. Should the application provide a near-seamless experience, giving the impression that the components are a native part of the parent page - like for instance a login widget, or should the widget give a branded and more isolated impression like the Facebook widget? Can the site be trusted? Should the web site or the users be allowed to interact with the application? Depending on the answers there are a number of different approaches, ranging from tight integration to sandboxed iframes. In this talk I will go into detail on the following subjects: - Loading and initializing the JavaScript application, - Running JavaScript and rendering HTML in unknown environments, - The balance between integration and sandboxing, - Communicating with other sites and components, - Security, and how to work around browser constraints
 Hello, everyone. Welcome to this talk. I'm going to be talking about building third-party widgets and APIs using JavaScript. I'll just start by saying some few things about myself. That's me in the picture right there on the right. A three-year soul playing around with my Commodore 64. My name is Thorsten Björnstapp. I work as a.NET consultant at Webstep here in Oslo. I consider myself a web developer. I've been working a lot with the.NET stack, but the past few years I've been doing more and more work on the website of things. You might be saying, I assume most of you know JavaScript. Yeah, I know what I mean when I say, when I'm going to talk about JavaScript, but third-party JavaScript. What is it really? I think of it like this, that the first part is the person using the web browser, looking at the web page and just using your page. And the second part, that's you guys, when you create websites for other people. So you write JavaScript running on a page, you know the environment that JavaScript is going to run in, and you know the other scripts on the page. And then you have third-party. Third-party providers of JavaScript don't know anything about the page that JavaScript is going to be displayed on or run on. So they're usually loaded from a different server, and they're probably updated independently of the actual web page that JavaScript is running on. And you don't know which frameworks are loaded on the page, and you can't really assume anything about the page that JavaScript is going to run on. So examples of third-party widgets can be, for instance, the Facebook widgets or Facebook widgets. There are a bunch of different Facebook widgets that are displayed on newspaper pages and everything. And they use your cookies when they're displayed, so they can show you information about your friends and what your friends have said about the current page. And then you have widgets, like, for instance, the discussed widgets that you have probably seen on web pages or blogs or newspapers and such in order to discuss the content of the actual page. And they give a quite powerful, threaded discussion model with avatars and everything. And they also have some admin panel where you can go and censor some posts, delete posts, and show everything about status of the widgets. And then you have, for instance, Twitter widgets that were supposed to be displayed on the page right now, but it's not. But I guess you've seen it a lot of times. It's typically the widget where you display a list of tweets, like the one on the big screen out in the hole, where you can see either all tweets regarding one search or one subject or all tweets for a person. And you also have more just plain API third-party JavaScripts, like Google Analytics, that don't really modify the DOM. They just provide the JavaScript API that you can use to report analytics back to Google so you can get everything there in the admin panel in Google Analytics. So in this talk, I'm going to be talking about how you can go about if you want to create a JavaScript widget of your own. This talk has three main sections. The first is just getting into the page and loading your first JavaScript file. And the second section is about modifying the DOM, how you can actually display content to the users, hopefully without destroying the page you're actually on. And the third part is getting data, sending data back to the server, and the security concerns regarding communication with JavaScript. So to start with, loading scripts. The first hardest part or natural point to start when you want to run JavaScript on someone else's page is to get the script actually to the page. And the most important thing here is you don't want to break the page. If someone puts your JavaScript on a page and actually destroys the page or makes it unusable, that's bad. So do not break the page at all. You have to be really careful when loading stuff. If you load any frameworks or libraries, you need to know are there, maybe they are already running on the page. So will they conflict? How are the versions? And for instance, you don't want to do JavaScript alerts. You don't want to do console logs. As in some versions of Internet Explorer, they will just fail. And you can, for instance, just load jQuery and hope it will work. You can say the page must have jQuery loaded in order to use your widget. But then again, there are a bunch of versions of jQuery. It might be modified. It might have some plugins loading into jQuery that won't work for you. And you can't really just load jQuery because those plugins that the page required might not work with your version of jQuery. So you've got to be really careful when loading jQuery. Maybe you can't really load jQuery at all, depending on the case. So there are a few things you can do because you probably need to load some libraries in order to run on the page. So you have to avoid conflicts with the scripts that might be running on the page. So the first thing is globals. You want to keep globals to minimum. Preferably no global variables at all. And if you need any, you can probably limit yourself to just one global variable. And if you're creating an API, you probably need one global variable. So you can just use that. So when you're loading JavaScript, when you're doing things in the page, use closures and immediately mode function expressions in order to keep your variables from registering in the global scope and maybe overriding some values that are already there. So if you want to load scripts, take a look at scripts supporting no conflict. You have, for instance, jQuery, underscore, and backbone. They have a method called no conflict, which after the scripts are loaded, you can call no conflict and they will remove themselves from the global namespace and restore the variable to the original value. That way you can just load jQuery, call no conflict, and keep a reference to the version of jQuery that you loaded while the page will still see the original version of jQuery. Just be careful when loading scripts like jQuery asynchronously when the page is loading plugins at the same time as those plugins might register on your version of jQuery instead of your other version of jQuery. So if you're loading scripts, you should try to wrap them. For instance, require.js supports, or it has an option for adding a wrapper around a script file. So when you do the optimizing build in require.js, it will hide the global scope from the script. So unless the script explicitly declares that this variable should be added to the window object, it will be added to your namespace instead. And in some cases, you might need to modify the scripts in order to have them not register to the global namespace. And if you're using require.js, you got to be aware that the variables define and require that require defines will also be in the global namespace by default. And there you have an option as well to put define and require into your own namespace. So you can just use the one global variable. And also when you're loading your own scripts, I recommend using some script loader like require.js so you won't have to put all your constructors and other factories and such into the global variable that you have. Because then other people might start to use your internal or private variables and you will have a hard time updating your scripts or changing your APIs later. So the best thing is if you are to put something into the global namespace, make sure that you only expose your public functionality. And another thing is you don't want to affect page load times. If your server goes down when someone references a JavaScript on your server, that's not really too bad. Because if your server is down, they typically get a 404 and the page just continues loading. The bad thing is if your server is overloaded for some reason, maybe someone including your script pulls something about just a be-brand, you get a lot of requests, then you start to reply really slowly to requests and things might start to block. So if your scripts load really slowly, that's bad. For instance, if your scripts are big, that's bad as well because the users will wait a long time for the scripts to download. And what happens when you deploy updates to your application and if your application pooled the recycles, then the next request might take some longer time to actually complete and the users will have a frozen page as well. So the big goal is that page should always just load as normal as possible and then your script should just load in addition to normal behavior. So I made an example application here. It's quite fancy, I think. These are some pictures of animals. And as you see, as soon as I refresh the page, all the pictures are grayed out. And then when I mouse over, I get this sweet pop-out effect. So I made this, I want to put it on Reddit or something, and then I want to visit the counter so I can see how many people have actually seen the page. So I made a very simple widget so I see how many people have visited this page. And you see, this doesn't really affect the page. The page shows up, the images show up immediately, and they're grayed out. And here I'm using a simple script tag, just like you would include, for instance, jQuery or something. And this works for the perfect case. The script serves quickly and the widget loads and everything is fine. But the problem is if this script takes a bit long to load, the page loading will block until the script has loaded and parsed and completed running. So you should at least put the script towards the bottom of the page. So at least the images will display and things will look quite nice for users. But you will notice that document ready will not trigger until your script has loaded or failed loading. So then we'll get the case where the images load, but they don't get grayed out because that's the JavaScript that's set to run on document ready. So let me see here. So this is the case. You see now I've created some delay when loading the script. And now you see the page loads and then a second later or so, one and a half seconds, then the widget loads and it displays the visitors. But until that happens, you see the images don't get grayed out and something looks off to the user. So you might think this can be solved by caching the script on the page or caching the script on the client. Then it would take just as long to load the first time, but at least it would be slow or at least it would be faster on reloads and when the user clicks on. It's not too bad if the visitor counter doesn't really display the correct value at all times. So we could cache the script for maybe a short while. But then we have the problem with updates. If we find some critical bug on some client's page and we really need to update the script and push it out to all the clients, then it's a problem if users have actually cached the script. So we need to find some solution. So the solution to actually enabling caching of the script is to use some sort of JavaScript loader. And it's quite simple, actually. We just, instead of loading the script directly on the page, we just add a reference to the loader and then when the loader is loaded, it has a reference to a version URL of the script. So loader in this case gets script version 15. And then it goes out, gets the script, and has the script to the page and then it's run. Then the script can be cached for, say, a year. So as long as the loader is never cached, the script can be cached forever. And then whenever you release a new version of the script, you update the loader to version 16 and things work. And of course, this won't help with if the server hosting the loader is low, but at least you'll solve the case with your script getting bigger. If you have included jQuery or backbone and lots of scripts and it's maybe half a megabyte, it's a good idea if you're able to cache it. So look at this example now. Now we see the page opens, the image is displaced, and they're grayed out immediately. And a while later, the counter is displayed at the bottom. So now we have the loader loading immediately, document ready is firing, and then one and a half seconds later, the script is loaded. So the loader is quite simple and you only need a couple of lines of code, so it will be quite fast to serve. And you can keep it in memory on the web server or something, put it on a CDN, so it will get served quickly. So you basically just create a script tag, set the source of the script tag, and then add it to the document. And as soon as the script tag is added to the document, it will get downloaded by the browser and then executed and run. And here you also see an example of the immediately invoked function expression that wraps the whole script, which prevents the script variable and the S variable from leaking out into the global namespace. So this script leaks no variables into global namespace. Yeah. Yeah. So I'll get back to that again. So as I mentioned on the previous slide, this is still a problem if the server with the loader is nonresponsive. So again, back to the example. Now we see the same, or actually it's worse than it was, because now we take one and a half seconds to first get the loader and then the loader adds the script before the counter appears at the bottom. So this doesn't really seem to have solved anything. But we can fix that as well. I'll get back to that. So you might be wondering why does script loading have to block the DOM anyway. For instance, in this case, it would be okay if document ready were to run and everything were to run because my script can run at any time, even after the page has loaded. And the answer is, of course, document write. Document write was included in JavaScript from way in the beginning. And it lets you write to the DOM exactly where the browser has come in the parsing. So if the browser, it starts at the top, starts parsing the HTML and then finds the JavaScript, if the JavaScript contains the document write statement, that will be written to the exact same point that the browser is at at the moment. And document write can add HTML, JavaScript, CSS, or anything to the page. So it might write something that will affect the rest of the parsing and the rest of the rendering of the DOM. So just in case, even though your script might not even include a document write statement, the browser has to stop, download the script, parse the script, run it. Normally afterwards, can it really be sure that nothing happened or at least it doesn't really care, then it can just continue parsing. So it would be nice if there's a way to say to the browser, don't care about document write, just load my script and run it. That's when we got the async keyword. We actually got the defer keyword in HTML4, which had logic that a script marked as defer would be loaded in order, or they would be loaded in parallel and then run in the same order. Async, which we got in HTML5, says just load the script and run it whenever it completes. So no matter if you're loading a big script and a small script, the small script will probably run before the big script. And of course, this is not supported everywhere, unfortunately. But we can get the same behavior using an async loader script. So we're getting a bit into inception here. This is instead of putting the script tag into your page, you put the script block into the page. You might have seen something like this for Google Analytics instead of inserting a script tag for the Google Analytics script. You're supposed to insert this weird big script block in your page instead. But the big advantage of this is that it will always get loaded asynchronously, independent of the browser. So what it does here, as I mentioned earlier, it just creates the script tag, sets the source, and also you should set the async attribute. As some browsers might stop parsing the page when it encounters the script tag if the page hasn't completed parsing already. So by setting the async property to true and adding the script dynamically like this, we're guaranteed to get async behavior when loading the script. So unfortunately, it's a bit ugly to say to everyone wanting to use your script that you have to put in these eight lines of JavaScript or how many it is on your web page. But that's just how it is. So if you go to the Google Analytics documentation, you will see, just put this script block in your code and it will work. So one thing when you get to loading is that you want to do loading right early. You want to get your loaders and the sequence of doing the async loading of the loader script and then doing the async loading of the main script. You want to get that right in your project right from the beginning because this is very hard to change later. As soon as someone has put in some script types for your script on their pages, it's really hard to get them to change that or update that later. And in the worst case, you will have to maintain separate versions of your script in order to support both the asynchronous loading and the synchronous loading. So if you just concentrate on getting the loading right early on and getting some code running on the consumer's page, then we can get working because now you have full power over the page. So over to displaying stuff. When you have scripts running on the page, you can just do whatever you are doing normally. You can, for instance, if you have reference for jQuery, you can add the, or use it to find DOM elements, add DOM elements, do anything. And you can also do that with just plain JavaScript APIs. And often the last option is often better because that's few dependencies that you need, especially on something as big as jQuery. It's better to add a few dependencies. So, yeah, when you want to put something on the page, just render it. But do not mess up the page. If you just want to show something simple like the visitor counter I showed you, then it's easy. Just put in an element with a screen on the page. But if you want to do something more fancy like the Facebook widget or the Twitter widget, you should be aware when you are starting to add CSS and start to the page. So you can load CSS on the page the way you normally add CSS on the page by actually rendering and you link tag to the page, set the href to the script or to the starsheet, and then just add it to the HTML. Then the starsheet will get loaded and apply to the page. Just be aware that you do not want to modify the styling of other elements on the page. So this is best if all the elements you are rendering on the page are put into one element, just like you want to put all the JavaScript variables into one global JavaScript variable. And then you can scope your CSS to just apply to elements within that one element with one given ID or class. So that will be your global variable in the HTML or in the DOM. And here is also nice to use something like less or less in order to create nested CSS. Nested CSS might get a bit ugly, but at least you will be able to create one global element, so to say, and then put everything under that. So it's a lot easier to modify the CSS or perhaps if you need to change the ID or the class of the one element. And you will also encounter cases where the scripts or the styles on the page will affect the styling of your elements. And then you will need to add explicit styling to your elements to override that. And then you will have to play around with specificity and create really specific CSS rules that sets the font size to whatever you want, the padding, margin and everything, even though you won't probably need it on your test page, but suddenly you have some consumer doing something weird with some weird rules and adding a padding to all divs, and then you have to override it. So one option here is to use iframes, and I will get back to that. And an optional problem or challenge is to not be affected by styling at all on the page. So no matter what the user or the owner of the page does, your script won't be affected. And one good example here is, for instance, the Facebook widget. The Facebook has very strict branding. Everything is the same blue color, same font, same buttons. And you won't be able to change the blue color to red or do anything weird with the widget or change the like button to just a normal link, fooling users into clicking it. So if you want to do that, you have to make something more interesting. You can just try to set more specific rules if it isn't that important, but if it's really important like the Facebook widget, you need to do something else. So one kind of neat thing is sourceless iframes. I read about sourceless iframes only a while ago, and I thought they were pretty cool because they let you create a sandbox inside the DOM for styles. So any styles on the actual page won't affect the elements inside the sourceless iframe, and any styles you apply inside the iframe won't affect the page outside. So that way you get a sandbox and you can actually do some communication in and out of the iframe. So it's not as strict as normal iframe. So if you have a script running on the page, you can display two iframes and communicate back and forth between the script and the iframes or the iframes. So in order to create the sourceless iframe, you just do what we did earlier to create dynamic elements, you create an iframe element, set various properties, not setting the source, and then adding the iframe to the DOM. And after the iframe has been added to the DOM, you will get access to its content window document property, which is kind of the same as the document property on the whole page, only in the iframe. And then you can write HTML to the iframe with document right or iframe document right in this case. And then you can add style tags, script tags, dynamic inside iframe, which will then get loaded and executed all in the sandbox of the iframe. And as you have access to the document object, you can set variables and do stuff with objects inside the iframe from outside of the iframe. But also can the page. So it's not secure. So, for instance, Facebook wouldn't want to use that because then every page embedding a Facebook widget would be able to get access to the list of friends, for instance, listed inside the widget. For that, you want to use normal iframe. So, normal iframes, I guess some of you have used, where you just set the source to a page. And this will be an absolute reference to a page existing on your web server, not a relative reference, as in this example. And they give you a full separation between the page and your widget. The browsers enforce that the iframe and the contents of the iframe come from different server, so you won't be able to communicate between the page and the widget. You have some options to do that, and I'll get back to that. But in this case, the page won't be able to get any access to the stuff inside the iframe. So I have some examples here to do some cases. For instance, if you're going to make some interactive widget, this is something I made for a project. It was a widget for creating like multiple choice-style tests, where you had some dynamic editor, you could add new elements, enter the question and the answers, and reorder them and delete them and so on. And this was designed to be integrated into other web pages showing various tests. And they also had a similar player for actually solving the tests. We did this by rendering everything directly into the DOM. We didn't know about iframes at that stage, and yeah, we thought it would be easy. We just styled it. And we ended up styling it a lot. Because there are some... Well, there are a lot of styles here that are necessary for actually presenting this in a good way. And as soon as the page did something to margins or paddings or paragraphs or divs or fonts or whatever, they affected us. So we had to be really explicit in all the styling and say, yeah, we had to override all the weird properties you can think of in order to make sure this looked like we want. One of the reasons we did it inside DOM was so they could be able to override some of the styles. So, for instance, the colors and fonts, perhaps, there were a few things that we would be allowed to edit. If I were to do this again, I would probably do it either as a source with an iframe or maybe just an iframe. Because of those handboxing, I would get with the styles. The styles were hard to do. If you want to do something like this with an iframe and you want to use some of the styles on the page, for instance, the background color, then you could, with your JavaScript on the page, try to extract out the font, maybe, or the background color and then pass it into the iframe so you can set the same properties inside the iframe. Another example is embedding, for instance, a YouTube video that you don't see there. But you have seen it on a lot of pages, just the big window with the video inside. The best thing there is to use something like an iframe. If you go to YouTube and you click share, you can get the HTML code for embedding an iframe and just put that into your page. And they could, instead, have used some, or they could have provided some third-party JavaScript with some API, like embed video with the code and it would add the iframe tag to your HTML. And iframes are good for something like videos or something where all they do is communicating with the server they're loaded from instead of communicating with your page. So you have to consider the communication patterns of the application. Will the widget communicate with your page or other widgets on the page? Then normal iframes might not be a good solution. But if they communicate mostly directly with the server they're loaded from, iframes will be good. And also one good thing about iframes is that the contents of the iframe is rendered by the server they're loaded from. So instead of having to create all the DOM elements dynamically using your JavaScript, they can just be rendered on the server directly. And that creates some nice separation and it's easier to create and easier to test. So you've got to remember that iframes are not really that bad. I think iframes have bad reputation. Probably because they came from Internet Explorer. But just like XML HTTP requests, iframes in XML HTTP requests are actually pretty good things we've got from Internet Explorer. One problem you can get with iframes is if you want to render something outside of frame, either you display some pop-up or tooltip, then you're going to get a problem. Because iframes can be considered as a window into the other web server and you can't really display anything outside the border of the window. So if you need to do that you can solve it by rendering the tooltip or the pop-up from the script running on the page instead. Or perhaps creating several iframes and combining them in weird ways. But you've got to think about performance if you're going to create several iframes. If you are making a lot of different elements on the page, then iframes might not be the best idea. It will give you a performance impact. And especially compared to just rendering plain DOM elements, they're quite slow. And inheriting styles, I mentioned. You can do it with iframes, but it's a bit difficult because you have to try to find out which font will be used to use several levels of the DOM hierarchy. But it's possible. And then you have security. If you need absolute security, then normal iframes are a lot better than or they're actually the only option. But if security is not too big of a concern, then you can load things either in the DOM or view sourced as iframes. And when I say securities, then I think about is there a problem if the page actually gets access to the contents of the iframe? For instance, showing your friends on Facebook is not a good idea, but if they just say the discussion fields, then that's okay. So now we go into data and security. You got to be aware of the security boundaries in the browser. The browser always tries to make sure that your data won't leak anywhere, of course. And everything in the browser is designed so when you make a request to another website, when you do a get JSON with jQuery, your cookies can get sent. And if, for instance, a page were able to just do a get to your Facebook friend page and your cookie was sent along with it and the data returned to the page, that would be really bad. So the browsers do enforce security boundaries between servers. And then you're creating a third-party JavaScript. The script and the data for the JavaScript is most likely located on a different domain and the same with the data. So you're going to encounter these security problems. Luckily, loading scripts and images are easy, but data is not. So you can start to use just whatever you're using, like jQuery, get JSON or Angular, or HTTP for loading the data. And then we have to do some tricks in order to actually allow the request to complete. So just something more about the same origin policy in browsers. The browsers have implemented, yeah, all browsers have implemented the same origin policy, even though not in the same way. And the point is that it's there to prevent XML HTTP requests to different sites using the users own credentials. So the requirement here is when you want to make the request, it's important that it's the same protocol as the pages that you're on, HTTP and HDS. And it has to be the same host as the page, including the subdomain. And it also has to be the same port as the page. And make note here that script tags and images, as mentioned, are exempt from the same origin policy. Luckily. So that's why we're allowed to load jQuery from CDN and so on. So in order to get past the same origin policy, we need to use something called cross-origin resource sharing that W3C has created. And this is for allowing requests across different origins than protocols, and ports, by using a pre-flight options request. So every time you then make a get request to the server, the browser first sends a pre-flight request, which is an HTTP option. And then the server responds with which methods and which headers are allowed for the actual response. So the server can, for instance, say, do not send cookies or do not do deletes. And here we have implementations in all browsers, but they vary a bit. So here's an overview of the support in the browsers. And as you see, all the major browsers support it. But be aware of that Internet Explorer 8 and 9. Only support get and post using course. And also you get problems if you want to use custom headers or send cookies. So authentication is a big problem here. So then you've got to do something like putting authentication tokens in the URLs or something. And you also need to be aware of that if your users are using Internet Explorer, you're going to encounter the Internet Explorer security sounds, if you're unlucky. And the problem here is you might have done everything correct with course and things are working in all browsers. Things work perfectly for you and in your local environment. And then some system administrator might have added your domain as a trusted site. And then web pages on the Internet won't be able to make requests to your trusted site. So then you won't be able to get data. And if this is set, there's nothing you really can do to get around it unless you've actually talked to the IT administrator and get them to remove your site from trusted sites. And this might be a big problem. So one thing you can do in order to load data from the server is to use JSON with padding, JSONP. JSONP is actually quite good workaround for same origin policy. It just works. It's very simple. It only works for get requests. So if you just want to fetch some simple data to display on the site and you are not going to include anything like any user secrets, for instance, Facebook, France, then JSONP is very good. So JSONP is actually just a script tag. So it's just a JavaScript file. It's not a JSON file. So you refer to JavaScript file with the callback. And then when you receive the JavaScript file, your JSON is returned to the page wrapped in the callback. So as soon as the JavaScript is parsed and executed, the callback will get called with the data you requested. And this works quite nice using jQuery. So for instance, if you do a get JSON and it notices there's a callback parameter in the URL, then jQuery will auto generate the callbacks for you and the API is just the same as using get JSON normally. And if you want to send data, you can do it through image tags. Google Analytics, for example, uses this in order to send analytics data. So just by creating a new image and setting the source, this request will be made to the server. And then you can add some parameters. Just be aware of the maximum length of the URL in various browsers and various web servers. So this is quite nice for just fire and forget, perfect for logging and logging statistics. For instance, this is a recounter. It would be perfect just implementing using this just to send data, not caring about the response. And then the web server can just return a 200 OK without no image, of course. And nothing is added to the DOM here. And then we have iframe messaging. Iframe, as I mentioned before, are kind of like windows or tunnels into a different server. And the nice thing is that everything running inside that iframe can communicate freely with the server. And there are some things you can do to actually communicate with the iframe as well. So iframe supports simple messaging. And it's quite hard. But, yeah, it's quite useful when you get it working. Because then it can work across all browsers and it works quite nice. And then you can tunnel jQuery and other messaging libraries through the iframe. So some suggestions in order to do communication is to consider course first. As it's standard, it's getting wider and wider support. And all newer browsers, not caring IE8 and IE9, support it quite well. All HTTP methods and everything work. You just have to create something to return that options response. And the browsers will just handle it transparently. You don't have to request the options response yourself. If you're only getting there, I recommend you just use JCP. It works. It works well across all browsers. Just be careful not to include anything user personal or anything in that response. Because every web page can just include a reference to mydata.js with a callback. And the user's cookies will get sent along with that request and you'll get a response with, for instance, personal user information. And iframe messaging works well when you get it working. Then it's, yeah, you can just set it up, get it working and not care about it anymore. So take a look at ECXDM, which is a good library that abstracts away all the other things about iframe messaging. As you got to do various tricks in various browsers in order to get it to work. In IE7, I think it uses flash in order to do some tricks to get some messages passed into the iframe. So providing an API, this is actually just a single slide. Because I have talked about most of what you need to do in order to provide an API. You just got to get the script on the page, as I already talked about. You can forget about DOM because you're only going to provide some JavaScript objects registered in the global namespace. And, yeah, just make sure not to expose a lot of private properties and private objects inside the global namespace because people might start to use your privates instead of just to define public API. And of course, your API needs to be stable at the various or at certain degree, depending on what you need to do. So, yeah, that's not really much more to say here. So just a summary. You got to get your loading loader really perfect to begin with. Get it right and then start using it. And as soon as you got that loader script running and loaded asynchronously, you can keep modifying it to fit your needs. Maybe loading parts of your scripts in parallel and, yeah, doing various tricks with the page. You got to be careful when you're doing changes to the DOM because you don't want to break the pages. You'll make your customers mad. And when you're going to get data or send data to the server, I can't really say anything else than good luck. It's quite hard to get it working perfectly, but it won't work. So hopefully it stays working. So some suggested reading. I got inspired to do this talk after I read this book. We used it a lot when doing some of the scripts we were doing at my client. And this goes through all the points I talked about in this presentation in addition to a lot more. And there's quite some finer details on authentication and cookies and eye frames that varies a lot between the browsers. So they have very good tables and overview of what works where and when. So any questions? Yeah. Well, one, well, require.js does about the same. It adds a script tag to the page with the script you're requiring. The problem is you first have to require.js. So you've got to require.js down to the page synchronously first before you can start loading scripts asynchronously. So you still get the same problem with getting the first script on the page asynchronously. Yeah, up there. One question. Is async loading scripts work with the script that do DOM manipulation like knockout in Angular? Yeah, I think that should work. I'm not quite sure. You probably just want to make sure you're doing the DOM manipulation in the correct stages of DOM rendering. For instance, if you have loaded and run before document ready has fired or after document ready has fired, just make sure the elements that you actually need are going to bind to existing the DOM. That shouldn't be a problem. Yeah. I guess that's it. Thank you. Thank you.
 Hello, everyone. Welcome to this talk. I'm going to be talking about building third-party  widgets and APIs using JavaScript. I'll just start by saying some few things about myself.  That's me in the picture right there on the right. A three-year soul playing around with  my Commodore 64. My name is Thorsten Björnstapp. I work as a.NET consultant at Webstep here  in Oslo. I consider myself a web developer. I've been working a lot with the.NET stack,  but the past few years I've been doing more and more work on the website of things. You  might be saying, I assume most of you know JavaScript. Yeah, I know what I mean when  I say, when I'm going to talk about JavaScript, but third-party JavaScript. What is it really?  I think of it like this, that the first part is the person using the web browser, looking  at the web page and just using your page. And the second part, that's you guys, when  you create websites for other people. So you write JavaScript running on a page, you know  the environment that JavaScript is going to run in, and you know the other scripts on  the page. And then you have third-party. Third-party providers of JavaScript don't know anything  about the page that JavaScript is going to be displayed on or run on. So they're usually  loaded from a different server, and they're probably updated independently of the actual  web page that JavaScript is running on. And you don't know which frameworks are loaded  on the page, and you can't really assume anything about the page that JavaScript is going to  run on. So examples of third-party widgets can be, for instance, the Facebook widgets  or Facebook widgets. There are a bunch of different Facebook widgets that are displayed  on newspaper pages and everything. And they use your cookies when they're displayed, so  they can show you information about your friends and what your friends have said about the  current page. And then you have widgets, like, for instance, the discussed widgets that you  have probably seen on web pages or blogs or newspapers and such in order to discuss the  content of the actual page. And they give a quite powerful, threaded discussion model  with avatars and everything. And they also have some admin panel where you can go and  censor some posts, delete posts, and show everything about status of the widgets. And  then you have, for instance, Twitter widgets that were supposed to be displayed on the  page right now, but it's not. But I guess you've seen it a lot of times. It's typically  the widget where you display a list of tweets, like the one on the big screen out in the  hole, where you can see either all tweets regarding one search or one subject or all  tweets for a person. And you also have more just plain API third-party JavaScripts, like  Google Analytics, that don't really modify the DOM. They just provide the JavaScript  API that you can use to report analytics back to Google so you can get everything there  in the admin panel in Google Analytics. So in this talk, I'm going to be talking about  how you can go about if you want to create a JavaScript widget of your own. This talk  has three main sections. The first is just getting into the page and loading your first  JavaScript file. And the second section is about modifying the DOM, how you can actually  display content to the users, hopefully without destroying the page you're actually on. And  the third part is getting data, sending data back to the server, and the security concerns  regarding communication with JavaScript. So to start with, loading scripts. The first  hardest part or natural point to start when you want to run JavaScript on someone else's  page is to get the script actually to the page. And the most important thing here is  you don't want to break the page. If someone puts your JavaScript on a page and actually  destroys the page or makes it unusable, that's bad. So do not break the page at all. You  have to be really careful when loading stuff. If you load any frameworks or libraries, you  need to know are there, maybe they are already running on the page. So will they conflict?  How are the versions? And for instance, you don't want to do JavaScript alerts. You don't  want to do console logs. As in some versions of Internet Explorer, they will just fail.  And you can, for instance, just load jQuery and hope it will work. You can say the page  must have jQuery loaded in order to use your widget. But then again, there are a bunch of  versions of jQuery. It might be modified. It might have some plugins loading into jQuery  that won't work for you. And you can't really just load jQuery because those plugins that  the page required might not work with your version of jQuery. So you've got to be really  careful when loading jQuery. Maybe you can't really load jQuery at all, depending on the  case. So there are a few things you can do because you probably need to load some libraries  in order to run on the page. So you have to avoid conflicts with the scripts that might  be running on the page. So the first thing is globals. You want to keep globals to minimum.  Preferably no global variables at all. And if you need any, you can probably limit yourself  to just one global variable. And if you're creating an API, you probably need one global  variable. So you can just use that. So when you're loading JavaScript, when you're doing  things in the page, use closures and immediately mode function expressions in order to keep  your variables from registering in the global scope and maybe overriding some values that  are already there. So if you want to load scripts, take a look at scripts supporting  no conflict. You have, for instance, jQuery, underscore, and backbone. They have a method  called no conflict, which after the scripts are loaded, you can call no conflict and they  will remove themselves from the global namespace and restore the variable to the original value.  That way you can just load jQuery, call no conflict, and keep a reference to the version  of jQuery that you loaded while the page will still see the original version of jQuery.  Just be careful when loading scripts like jQuery asynchronously when the page is loading  plugins at the same time as those plugins might register on your version of jQuery instead  of your other version of jQuery. So if you're loading scripts, you should try to  wrap them. For instance, require.js supports, or it has an option for adding a wrapper around  a script file. So when you do the optimizing build in require.js, it will hide the global  scope from the script. So unless the script explicitly declares that this variable should  be added to the window object, it will be added to your namespace instead. And in some  cases, you might need to modify the scripts in order to have them not register to the  global namespace. And if you're using require.js, you got to be aware that the variables define  and require that require defines will also be in the global namespace by default. And  there you have an option as well to put define and require into your own namespace. So you  can just use the one global variable. And also when you're loading your own scripts,  I recommend using some script loader like require.js so you won't have to put all your  constructors and other factories and such into the global variable that you have. Because  then other people might start to use your internal or private variables and you will  have a hard time updating your scripts or changing your APIs later. So the best thing  is if you are to put something into the global namespace, make sure that you only expose  your public functionality. And another thing is you don't want to affect page load times.  If your server goes down when someone references a JavaScript on your server, that's not really  too bad. Because if your server is down, they typically get a 404 and the page just continues  loading. The bad thing is if your server is overloaded for some reason, maybe someone  including your script pulls something about just a be-brand, you get a lot of requests,  then you start to reply really slowly to requests and things might start to block. So if your  scripts load really slowly, that's bad. For instance, if your scripts are big, that's  bad as well because the users will wait a long time for the scripts to download. And  what happens when you deploy updates to your application and if your application pooled  the recycles, then the next request might take some longer time to actually complete  and the users will have a frozen page as well. So the big goal is that page should always  just load as normal as possible and then your script should just load in addition to normal  behavior. So I made an example application here. It's quite fancy, I think. These are  some pictures of animals. And as you see, as soon as I refresh the page, all the pictures  are grayed out. And then when I mouse over, I get this sweet pop-out effect. So I made  this, I want to put it on Reddit or something, and then I want to visit the counter so I  can see how many people have actually seen the page. So I made a very simple widget so  I see how many people have visited this page. And you see, this doesn't really affect the  page. The page shows up, the images show up immediately, and they're grayed out. And  here I'm using a simple script tag, just like you would include, for instance, jQuery  or something. And this works for the perfect case. The script serves quickly and the widget  loads and everything is fine. But the problem is if this script takes a bit long to load,  the page loading will block until the script has loaded and parsed and completed running.  So you should at least put the script towards the bottom of the page. So at least the images  will display and things will look quite nice for users. But you will notice that document  ready will not trigger until your script has loaded or failed loading. So then we'll get  the case where the images load, but they don't get grayed out because that's the JavaScript  that's set to run on document ready. So let me see here. So this is the case. You see  now I've created some delay when loading the script. And now you see the page loads and  then a second later or so, one and a half seconds, then the widget loads and it displays  the visitors. But until that happens, you see the images don't get grayed out and something  looks off to the user. So you might think this can be solved by caching the script on  the page or caching the script on the client. Then it would take just as long to load the  first time, but at least it would be slow or at least it would be faster on reloads  and when the user clicks on. It's not too bad if the visitor counter doesn't really display  the correct value at all times. So we could cache the script for maybe a short while.  But then we have the problem with updates. If we find some critical bug on some client's  page and we really need to update the script and push it out to all the clients, then it's  a problem if users have actually cached the script. So we need to find some solution.  So the solution to actually enabling caching of the script is to use some sort of JavaScript  loader. And it's quite simple, actually. We just, instead of loading the script directly  on the page, we just add a reference to the loader and then when the loader is loaded,  it has a reference to a version URL of the script. So loader in this case gets script  version 15. And then it goes out, gets the script, and has the script to the page and  then it's run. Then the script can be cached for, say, a year. So as long as the loader  is never cached, the script can be cached forever. And then whenever you release a new  version of the script, you update the loader to version 16 and things work. And of course,  this won't help with if the server hosting the loader is low, but at least you'll solve  the case with your script getting bigger. If you have included jQuery or backbone and  lots of scripts and it's maybe half a megabyte, it's a good idea if you're able to cache it.  So look at this example now. Now we see the page opens, the image is displaced, and they're  grayed out immediately. And a while later, the counter is displayed at the bottom. So  now we have the loader loading immediately, document ready is firing, and then one and  a half seconds later, the script is loaded. So the loader is quite simple and you only  need a couple of lines of code, so it will be quite fast to serve. And you can keep it  in memory on the web server or something, put it on a CDN, so it will get served quickly.  So you basically just create a script tag, set the source of the script tag, and then  add it to the document. And as soon as the script tag is added to the document, it will  get downloaded by the browser and then executed and run. And here you also see an example  of the immediately invoked function expression that wraps the whole script, which prevents  the script variable and the S variable from leaking out into the global namespace. So  this script leaks no variables into global namespace. Yeah. Yeah. So I'll get back to  that again. So as I mentioned on the previous slide, this is still a problem if the server  with the loader is nonresponsive. So again, back to the example. Now we see the same,  or actually it's worse than it was, because now we take one and a half seconds to first  get the loader and then the loader adds the script before the counter appears at the bottom.  So this doesn't really seem to have solved anything. But we can fix that as well. I'll  get back to that. So you might be wondering why does script loading have to block the  DOM anyway. For instance, in this case, it would be okay if document ready were to run  and everything were to run because my script can run at any time, even after the page has  loaded. And the answer is, of course, document write. Document write was included in JavaScript  from way in the beginning. And it lets you write to the DOM exactly where the browser  has come in the parsing. So if the browser, it starts at the top, starts parsing the HTML  and then finds the JavaScript, if the JavaScript contains the document write statement, that  will be written to the exact same point that the browser is at at the moment. And document  write can add HTML, JavaScript, CSS, or anything to the page. So it might write something that  will affect the rest of the parsing and the rest of the rendering of the DOM. So just in  case, even though your script might not even include a document write statement, the browser  has to stop, download the script, parse the script, run it. Normally afterwards, can it  really be sure that nothing happened or at least it doesn't really care, then it can  just continue parsing. So it would be nice if there's a way to say to the browser, don't  care about document write, just load my script and run it. That's when we got the async keyword.  We actually got the defer keyword in HTML4, which had logic that a script marked as defer  would be loaded in order, or they would be loaded in parallel and then run in the same  order. Async, which we got in HTML5, says just load the script and run it whenever it  completes. So no matter if you're loading a big script and a small script, the small  script will probably run before the big script. And of course, this is not supported everywhere,  unfortunately. But we can get the same behavior using an async loader script. So we're getting  a bit into inception here. This is instead of putting the script tag into your page,  you put the script block into the page. You might have seen something like this for Google  Analytics instead of inserting a script tag for the Google Analytics script. You're supposed  to insert this weird big script block in your page instead. But the big advantage of this  is that it will always get loaded asynchronously, independent of the browser. So what it does  here, as I mentioned earlier, it just creates the script tag, sets the source, and also  you should set the async attribute. As some browsers might stop parsing the page when  it encounters the script tag if the page hasn't completed parsing already. So by setting the  async property to true and adding the script dynamically like this, we're guaranteed to  get async behavior when loading the script. So unfortunately, it's a bit ugly to say to  everyone wanting to use your script that you have to put in these eight lines of JavaScript  or how many it is on your web page. But that's just how it is. So if you go to the Google  Analytics documentation, you will see, just put this script block in your code and it  will work. So one thing when you get to loading is that you want to do loading right early.  You want to get your loaders and the sequence of doing the async loading of the loader script  and then doing the async loading of the main script. You want to get that right in your  project right from the beginning because this is very hard to change later. As soon as someone  has put in some script types for your script on their pages, it's really hard to get them  to change that or update that later. And in the worst case, you will have to maintain separate  versions of your script in order to support both the asynchronous loading and the synchronous  loading. So if you just concentrate on getting the loading right early on and getting some  code running on the consumer's page, then we can get working because now you have full  power over the page. So over to displaying stuff. When you have scripts running on the  page, you can just do whatever you are doing normally. You can, for instance, if you have  reference for jQuery, you can add the, or use it to find DOM elements, add DOM elements,  do anything. And you can also do that with just plain JavaScript APIs. And often the  last option is often better because that's few dependencies that you need, especially  on something as big as jQuery. It's better to add a few dependencies. So, yeah, when  you want to put something on the page, just render it. But do not mess up the page. If  you just want to show something simple like the visitor counter I showed you, then it's  easy. Just put in an element with a screen on the page. But if you want to do something  more fancy like the Facebook widget or the Twitter widget, you should be aware when you  are starting to add CSS and start to the page. So you can load CSS on the page the way you  normally add CSS on the page by actually rendering and you link tag to the page, set the href  to the script or to the starsheet, and then just add it to the HTML. Then the starsheet  will get loaded and apply to the page. Just be aware that you do not want to modify the  styling of other elements on the page. So this is best if all the elements you are rendering  on the page are put into one element, just like you want to put all the JavaScript variables  into one global JavaScript variable. And then you can scope your CSS to just apply to elements  within that one element with one given ID or class. So that will be your global variable  in the HTML or in the DOM. And here is also nice to use something like less or less in  order to create nested CSS. Nested CSS might get a bit ugly, but at least you will be able  to create one global element, so to say, and then put everything under that. So it's a  lot easier to modify the CSS or perhaps if you need to change the ID or the class of  the one element. And you will also encounter cases where the scripts or the styles on the  page will affect the styling of your elements. And then you will need to add explicit styling  to your elements to override that. And then you will have to play around with specificity  and create really specific CSS rules that sets the font size to whatever you want, the  padding, margin and everything, even though you won't probably need it on your test page,  but suddenly you have some consumer doing something weird with some weird rules and adding a padding  to all divs, and then you have to override it. So one option here is to use iframes,  and I will get back to that. And an optional problem or challenge is to not be affected  by styling at all on the page. So no matter what the user or the owner of the page does,  your script won't be affected. And one good example here is, for instance, the Facebook  widget. The Facebook has very strict branding. Everything is the same blue color, same font,  same buttons. And you won't be able to change the blue color to red or do anything weird  with the widget or change the like button to just a normal link, fooling users into clicking  it. So if you want to do that, you have to make something more interesting. You can just  try to set more specific rules if it isn't that important, but if it's really important  like the Facebook widget, you need to do something else. So one kind of neat thing is sourceless  iframes. I read about sourceless iframes only a while ago, and I thought they were pretty  cool because they let you create a sandbox inside the DOM for styles. So any styles on  the actual page won't affect the elements inside the sourceless iframe, and any styles  you apply inside the iframe won't affect the page outside. So that way you get a sandbox  and you can actually do some communication in and out of the iframe. So it's not as strict  as normal iframe. So if you have a script running on the page, you can display two iframes  and communicate back and forth between the script and the iframes or the iframes. So  in order to create the sourceless iframe, you just do what we did earlier to create dynamic  elements, you create an iframe element, set various properties, not setting the source,  and then adding the iframe to the DOM. And after the iframe has been added to the DOM,  you will get access to its content window document property, which is kind of the same  as the document property on the whole page, only in the iframe. And then you can write  HTML to the iframe with document right or iframe document right in this case. And then  you can add style tags, script tags, dynamic inside iframe, which will then get loaded  and executed all in the sandbox of the iframe. And as you have access to the document object,  you can set variables and do stuff with objects inside the iframe from outside of the iframe.  But also can the page. So it's not secure. So, for instance, Facebook wouldn't want to  use that because then every page embedding a Facebook widget would be able to get access  to the list of friends, for instance, listed inside the widget. For that, you want to use  normal iframe. So, normal iframes, I guess some of you have used, where you just set  the source to a page. And this will be an absolute reference to a page existing on your  web server, not a relative reference, as in this example. And they give you a full separation  between the page and your widget. The browsers enforce that the iframe and the contents of  the iframe come from different server, so you won't be able to communicate between the  page and the widget. You have some options to do that, and I'll get back to that. But  in this case, the page won't be able to get any access to the stuff inside the iframe.  So I have some examples here to do some cases. For instance, if you're going to make some  interactive widget, this is something I made for a project. It was a widget for creating  like multiple choice-style tests, where you had some dynamic editor, you could add new  elements, enter the question and the answers, and reorder them and delete them and so on.  And this was designed to be integrated into other web pages showing various tests. And  they also had a similar player for actually solving the tests. We did this by rendering  everything directly into the DOM. We didn't know about iframes at that stage, and yeah,  we thought it would be easy. We just styled it. And we ended up styling it a lot. Because  there are some... Well, there are a lot of styles here that are necessary for actually  presenting this in a good way. And as soon as the page did something to margins or paddings  or paragraphs or divs or fonts or whatever, they affected us. So we had to be really explicit  in all the styling and say, yeah, we had to override all the weird properties you can think  of in order to make sure this looked like we want. One of the reasons we did it inside  DOM was so they could be able to override some of the styles. So, for instance, the colors  and fonts, perhaps, there were a few things that we would be allowed to edit. If I were  to do this again, I would probably do it either as a source with an iframe or maybe just an  iframe. Because of those handboxing, I would get with the styles. The styles were hard  to do. If you want to do something like this with an iframe and you want to use some of  the styles on the page, for instance, the background color, then you could, with your  JavaScript on the page, try to extract out the font, maybe, or the background color and  then pass it into the iframe so you can set the same properties inside the iframe. Another  example is embedding, for instance, a YouTube video that you don't see there. But you have  seen it on a lot of pages, just the big window with the video inside. The best thing there  is to use something like an iframe. If you go to YouTube and you click share, you can  get the HTML code for embedding an iframe and just put that into your page. And they  could, instead, have used some, or they could have provided some third-party JavaScript with  some API, like embed video with the code and it would add the iframe tag to your HTML.  And iframes are good for something like videos or something where all they do is communicating  with the server they're loaded from instead of communicating with your page. So you have  to consider the communication patterns of the application. Will the widget communicate  with your page or other widgets on the page? Then normal iframes might not be a good solution.  But if they communicate mostly directly with the server they're loaded from, iframes will  be good. And also one good thing about iframes is that the contents of the iframe is rendered  by the server they're loaded from. So instead of having to create all the DOM elements dynamically  using your JavaScript, they can just be rendered on the server directly. And that creates some  nice separation and it's easier to create and easier to test.  So you've got to remember that iframes are not really that bad. I think iframes have  bad reputation. Probably because they came from Internet Explorer. But just like XML  HTTP requests, iframes in XML HTTP requests are actually pretty good things we've got from  Internet Explorer. One problem you can get with iframes is if you want to render something  outside of frame, either you display some pop-up or tooltip, then you're going to get  a problem. Because iframes can be considered as a window into the other web server and  you can't really display anything outside the border of the window. So if you need to  do that you can solve it by rendering the tooltip or the pop-up from the script running  on the page instead. Or perhaps creating several iframes and combining them in weird ways.  But you've got to think about performance if you're going to create several iframes.  If you are making a lot of different elements on the page, then iframes might not be the  best idea. It will give you a performance impact. And especially compared to just rendering  plain DOM elements, they're quite slow. And inheriting styles, I mentioned. You can do  it with iframes, but it's a bit difficult because you have to try to find out which font  will be used to use several levels of the DOM hierarchy. But it's possible. And then  you have security. If you need absolute security, then normal iframes are a lot better than  or they're actually the only option. But if security is not too big of a concern, then  you can load things either in the DOM or view sourced as iframes. And when I say securities,  then I think about is there a problem if the page actually gets access to the contents  of the iframe? For instance, showing your friends on Facebook is not a good idea, but  if they just say the discussion fields, then that's okay. So now we go into data and security.  You got to be aware of the security boundaries in the browser. The browser always tries to  make sure that your data won't leak anywhere, of course. And everything in the browser is  designed so when you make a request to another website, when you do a get JSON with jQuery,  your cookies can get sent. And if, for instance, a page were able to just do a get to your  Facebook friend page and your cookie was sent along with it and the data returned to the  page, that would be really bad. So the browsers do enforce security boundaries between servers.  And then you're creating a third-party JavaScript. The script and the data for the JavaScript  is most likely located on a different domain and the same with the data. So you're going  to encounter these security problems. Luckily, loading scripts and images are easy, but data  is not. So you can start to use just whatever you're using, like jQuery, get JSON or Angular,  or HTTP for loading the data. And then we have to do some tricks in order to actually  allow the request to complete. So just something more about the same origin policy in browsers.  The browsers have implemented, yeah, all browsers have implemented the same origin policy, even  though not in the same way. And the point is that it's there to prevent XML HTTP requests  to different sites using the users own credentials. So the requirement here is when you want to  make the request, it's important that it's the same protocol as the pages that you're  on, HTTP and HDS. And it has to be the same host as the page, including the subdomain.  And it also has to be the same port as the page. And make note here that script tags  and images, as mentioned, are exempt from the same origin policy. Luckily. So that's  why we're allowed to load jQuery from CDN and so on. So in order to get past the same  origin policy, we need to use something called cross-origin resource sharing that W3C has  created. And this is for allowing requests across different origins than protocols,  and ports, by using a pre-flight options request. So every time you then make a get request  to the server, the browser first sends a pre-flight request, which is an HTTP option. And then  the server responds with which methods and which headers are allowed for the actual response.  So the server can, for instance, say, do not send cookies or do not do deletes. And here  we have implementations in all browsers, but they vary a bit. So here's an overview of the  support in the browsers. And as you see, all the major browsers support it. But be aware  of that Internet Explorer 8 and 9. Only support get and post using course. And also you get  problems if you want to use custom headers or send cookies. So authentication is a big  problem here. So then you've got to do something like putting authentication tokens in the  URLs or something. And you also need to be aware of that if your users are using Internet  Explorer, you're going to encounter the Internet Explorer security sounds, if you're unlucky.  And the problem here is you might have done everything correct with course and things  are working in all browsers. Things work perfectly for you and in your local environment. And  then some system administrator might have added your domain as a trusted site. And then web  pages on the Internet won't be able to make requests to your trusted site. So then you  won't be able to get data. And if this is set, there's nothing you really can do to  get around it unless you've actually talked to the IT administrator and get them to remove  your site from trusted sites. And this might be a big problem. So one thing you can do  in order to load data from the server is to use JSON with padding, JSONP. JSONP is actually  quite good workaround for same origin policy. It just works. It's very simple. It only works  for get requests. So if you just want to fetch some simple data to display on the site and  you are not going to include anything like any user secrets, for instance, Facebook,  France, then JSONP is very good. So JSONP is actually just a script tag. So it's just  a JavaScript file. It's not a JSON file. So you refer to JavaScript file with the callback.  And then when you receive the JavaScript file, your JSON is returned to the page wrapped  in the callback. So as soon as the JavaScript is parsed and executed, the callback will  get called with the data you requested. And this works quite nice using jQuery. So for  instance, if you do a get JSON and it notices there's a callback parameter in the URL, then  jQuery will auto generate the callbacks for you and the API is just the same as using  get JSON normally. And if you want to send data, you can do it through image tags. Google  Analytics, for example, uses this in order to send analytics data. So just by creating  a new image and setting the source, this request will be made to the server. And then you can  add some parameters. Just be aware of the maximum length of the URL in various browsers  and various web servers. So this is quite nice for just fire and forget, perfect for  logging and logging statistics. For instance, this is a recounter. It would be perfect just  implementing using this just to send data, not caring about the response. And then the  web server can just return a 200 OK without no image, of course. And nothing is added  to the DOM here. And then we have iframe messaging. Iframe, as I mentioned before, are kind of  like windows or tunnels into a different server. And the nice thing is that everything running  inside that iframe can communicate freely with the server. And there are some things  you can do to actually communicate with the iframe as well. So iframe supports simple  messaging. And it's quite hard. But, yeah, it's quite useful when you get it working.  Because then it can work across all browsers and it works quite nice. And then you can  tunnel jQuery and other messaging libraries through the iframe. So some suggestions in  order to do communication is to consider course first. As it's standard, it's getting wider  and wider support. And all newer browsers, not caring IE8 and IE9, support it quite well.  All HTTP methods and everything work. You just have to create something to return that  options response. And the browsers will just handle it transparently. You don't have to  request the options response yourself. If you're only getting there, I recommend you  just use JCP. It works. It works well across all browsers. Just be careful not to include  anything user personal or anything in that response. Because every web page can just  include a reference to mydata.js with a callback. And the user's cookies will get sent along  with that request and you'll get a response with, for instance, personal user information.  And iframe messaging works well when you get it working. Then it's, yeah, you can just  set it up, get it working and not care about it anymore. So take a look at ECXDM, which  is a good library that abstracts away all the other things about iframe messaging. As you  got to do various tricks in various browsers in order to get it to work. In IE7, I think  it uses flash in order to do some tricks to get some messages passed into the iframe.  So providing an API, this is actually just a single slide. Because I have talked about  most of what you need to do in order to provide an API. You just got to get the script on  the page, as I already talked about. You can forget about DOM because you're only going  to provide some JavaScript objects registered in the global namespace. And, yeah, just make  sure not to expose a lot of private properties and private objects inside the global namespace  because people might start to use your privates instead of just to define public API. And  of course, your API needs to be stable at the various or at certain degree, depending  on what you need to do. So, yeah, that's not really much more to say here. So just a summary.  You got to get your loading loader really perfect to begin with. Get it right and then  start using it. And as soon as you got that loader script running and loaded asynchronously,  you can keep modifying it to fit your needs. Maybe loading parts of your scripts in parallel  and, yeah, doing various tricks with the page. You got to be careful when you're doing changes  to the DOM because you don't want to break the pages. You'll make your customers mad.  And when you're going to get data or send data to the server, I can't really say anything  else than good luck. It's quite hard to get it working perfectly, but it won't work. So  hopefully it stays working. So some suggested reading. I got inspired to do this talk after  I read this book. We used it a lot when doing some of the scripts we were doing at my client.  And this goes through all the points I talked about in this presentation in addition to  a lot more. And there's quite some finer details on authentication and cookies and eye frames  that varies a lot between the browsers. So they have very good tables and overview of  what works where and when. So any questions? Yeah.  Well, one, well, require.js does about the same. It adds a script tag to the page with  the script you're requiring. The problem is you first have to require.js. So you've got  to require.js down to the page synchronously first before you can start loading scripts  asynchronously. So you still get the same problem with getting the first script on the  page asynchronously. Yeah, up there.  One question. Is async loading scripts work with the script that do DOM manipulation  like knockout in Angular?  Yeah, I think that should work. I'm not quite sure. You probably just want to make sure  you're doing the DOM manipulation in the correct stages of DOM rendering. For instance, if  you have loaded and run before document ready has fired or after document ready has fired,  just make sure the elements that you actually need are going to bind to existing the DOM.  That shouldn't be a problem. Yeah. I guess that's it.  Thank you.  Thank you.
Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_0_107.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_108_1175.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_1176_2207.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_2208_2723.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_2724_4955.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_4956_8987.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_8988_15143.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_15144_16055.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_16056_16163.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_16164_16967.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_16968_17555.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_17556_17927.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_17928_18035.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_18036_18107.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_18108_21143.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_21144_21227.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_21228_21683.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_21684_23483.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_23484_23987.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_23988_29051.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_29052_30299.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_30300_31919.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_31920_34463.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_34464_34559.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_34560_38063.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_38064_39047.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_39048_39515.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_39516_42563.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_42564_49367.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_49368_50639.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_50640_50963.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_50964_53735.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_53736_61079.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_61080_63443.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_63444_65963.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_65964_66767.png Torstein_Bj__rnstad_-_Building_Third-party_Widgets_and_APIs_using_JavaScript-68378924_66768_66867.png