app_view.js revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5var DocumentNatives = requireNative('document_natives'); 6var GuestViewInternal = 7 require('binding').Binding.create('guestViewInternal').generate(); 8var IdGenerator = requireNative('id_generator'); 9 10function AppViewInternal(appviewNode) { 11 privates(appviewNode).internal = this; 12 this.appviewNode = appviewNode; 13 14 this.browserPluginNode = this.createBrowserPluginNode(); 15 var shadowRoot = this.appviewNode.createShadowRoot(); 16 shadowRoot.appendChild(this.browserPluginNode); 17 this.viewInstanceId = IdGenerator.GetNextId(); 18} 19 20AppViewInternal.prototype.getErrorNode = function() { 21 if (!this.errorNode) { 22 this.errorNode = document.createElement('div'); 23 this.errorNode.innerText = 'Unable to connect to app.'; 24 this.errorNode.style.position = 'absolute'; 25 this.errorNode.style.left = '0px'; 26 this.errorNode.style.top = '0px'; 27 this.errorNode.style.width = '100%'; 28 this.errorNode.style.height = '100%'; 29 this.appviewNode.shadowRoot.appendChild(this.errorNode); 30 } 31 return this.errorNode; 32}; 33 34AppViewInternal.prototype.createBrowserPluginNode = function() { 35 // We create BrowserPlugin as a custom element in order to observe changes 36 // to attributes synchronously. 37 var browserPluginNode = new AppViewInternal.BrowserPlugin(); 38 privates(browserPluginNode).internal = this; 39 return browserPluginNode; 40}; 41 42AppViewInternal.prototype.connect = function(app, callback) { 43 var params = { 44 'appId': app 45 }; 46 var self = this; 47 GuestViewInternal.createGuest( 48 'appview', 49 params, 50 function(instanceId) { 51 if (!instanceId) { 52 self.browserPluginNode.style.visibility = 'hidden'; 53 var errorMsg = 'Unable to connect to app "' + app + '".'; 54 window.console.warn(errorMsg); 55 self.getErrorNode().innerText = errorMsg; 56 if (callback) { 57 callback(false); 58 } 59 return; 60 } 61 self.attachWindow(instanceId); 62 if (callback) { 63 callback(true); 64 } 65 } 66 ); 67}; 68 69AppViewInternal.prototype.attachWindow = function(instanceId) { 70 this.instanceId = instanceId; 71 var params = { 72 'instanceId': this.viewInstanceId, 73 }; 74 this.browserPluginNode.style.visibility = 'visible'; 75 return this.browserPluginNode['-internal-attach'](instanceId, params); 76}; 77 78function registerBrowserPluginElement() { 79 var proto = Object.create(HTMLObjectElement.prototype); 80 81 proto.createdCallback = function() { 82 this.setAttribute('type', 'application/browser-plugin'); 83 this.style.width = '100%'; 84 this.style.height = '100%'; 85 }; 86 87 proto.attachedCallback = function() { 88 // Load the plugin immediately. 89 var unused = this.nonExistentAttribute; 90 }; 91 92 AppViewInternal.BrowserPlugin = 93 DocumentNatives.RegisterElement('appplugin', {extends: 'object', 94 prototype: proto}); 95 96 delete proto.createdCallback; 97 delete proto.attachedCallback; 98 delete proto.detachedCallback; 99 delete proto.attributeChangedCallback; 100} 101 102function registerAppViewElement() { 103 var proto = Object.create(HTMLElement.prototype); 104 105 proto.createdCallback = function() { 106 new AppViewInternal(this); 107 }; 108 109 proto.connect = function() { 110 var internal = privates(this).internal; 111 $Function.apply(internal.connect, internal, arguments); 112 } 113 window.AppView = 114 DocumentNatives.RegisterElement('appview', {prototype: proto}); 115 116 // Delete the callbacks so developers cannot call them and produce unexpected 117 // behavior. 118 delete proto.createdCallback; 119 delete proto.attachedCallback; 120 delete proto.detachedCallback; 121 delete proto.attributeChangedCallback; 122} 123 124var useCapture = true; 125window.addEventListener('readystatechange', function listener(event) { 126 if (document.readyState == 'loading') 127 return; 128 129 registerBrowserPluginElement(); 130 registerAppViewElement(); 131 window.removeEventListener(event.type, listener, useCapture); 132}, useCapture); 133