SHINDIG-1056 by lipeng, BasicRemoteContentTest doesn't depend on static private key...
[shindig.git] / javascript / container / gadgets.js
blobd0bd2553cce5e4a125949273c4e1fb9561984e40
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations under the License.
19 /**
20 * @fileoverview Open Gadget Container
23 var gadgets = gadgets || {};
25 gadgets.error = {};
26 gadgets.error.SUBCLASS_RESPONSIBILITY = 'subclass responsibility';
27 gadgets.error.TO_BE_DONE = 'to be done';
29 gadgets.log = function(message) {
30 if (window.console && console.log) {
31 console.log(message);
32 } else {
33 var logEntry = document.createElement('div');
34 logEntry.className = 'gadgets-log-entry';
35 logEntry.innerHTML = message;
36 document.body.appendChild(logEntry);
40 /**
41 * Calls an array of asynchronous functions and calls the continuation
42 * function when all are done.
43 * @param {Array} functions Array of asynchronous functions, each taking
44 * one argument that is the continuation function that handles the result
45 * That is, each function is something like the following:
46 * function(continuation) {
47 * // compute result asynchronously
48 * continuation(result);
49 * }
50 * @param {Function} continuation Function to call when all results are in. It
51 * is pass an array of all results of all functions
52 * @param {Object} opt_this Optional object used as "this" when calling each
53 * function
55 gadgets.callAsyncAndJoin = function(functions, continuation, opt_this) {
56 var pending = functions.length;
57 var results = [];
58 for (var i = 0; i < functions.length; i++) {
59 // we need a wrapper here because i changes and we need one index
60 // variable per closure
61 var wrapper = function(index) {
62 functions[index].call(opt_this, function(result) {
63 results[index] = result;
64 if (--pending === 0) {
65 continuation(results);
67 });
69 wrapper(i);
74 // ----------
75 // Extensible
77 gadgets.Extensible = function() {
80 /**
81 * Sets the dependencies.
82 * @param {Object} dependencies Object whose properties are set on this
83 * container as dependencies
85 gadgets.Extensible.prototype.setDependencies = function(dependencies) {
86 for (var p in dependencies) {
87 this[p] = dependencies[p];
91 /**
92 * Returns a dependency given its name.
93 * @param {String} name Name of dependency
94 * @return {Object} Dependency with that name or undefined if not found
96 gadgets.Extensible.prototype.getDependencies = function(name) {
97 return this[name];
102 // -------------
103 // UserPrefStore
106 * User preference store interface.
107 * @constructor
109 gadgets.UserPrefStore = function() {
113 * Gets all user preferences of a gadget.
114 * @param {Object} gadget Gadget object
115 * @return {Object} All user preference of given gadget
117 gadgets.UserPrefStore.prototype.getPrefs = function(gadget) {
118 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
122 * Saves user preferences of a gadget in the store.
123 * @param {Object} gadget Gadget object
124 * @param {Object} prefs User preferences
126 gadgets.UserPrefStore.prototype.savePrefs = function(gadget) {
127 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
131 // -------------
132 // DefaultUserPrefStore
135 * User preference store implementation.
136 * TODO: Turn this into a real implementation that is production safe
137 * @constructor
139 gadgets.DefaultUserPrefStore = function() {
140 gadgets.UserPrefStore.call(this);
142 gadgets.DefaultUserPrefStore.inherits(gadgets.UserPrefStore);
144 gadgets.DefaultUserPrefStore.prototype.getPrefs = function(gadget) { };
146 gadgets.DefaultUserPrefStore.prototype.savePrefs = function(gadget) { };
149 // -------------
150 // GadgetService
153 * Interface of service provided to gadgets for resizing gadgets,
154 * setting title, etc.
155 * @constructor
157 gadgets.GadgetService = function() {
160 gadgets.GadgetService.prototype.setHeight = function(elementId, height) {
161 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
164 gadgets.GadgetService.prototype.setTitle = function(gadget, title) {
165 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
168 gadgets.GadgetService.prototype.setUserPref = function(id) {
169 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
173 // ----------------
174 // IfrGadgetService
177 * Base implementation of GadgetService.
178 * @constructor
180 gadgets.IfrGadgetService = function() {
181 gadgets.GadgetService.call(this);
182 gadgets.rpc.register('resize_iframe', this.setHeight);
183 gadgets.rpc.register('set_pref', this.setUserPref);
184 gadgets.rpc.register('set_title', this.setTitle);
185 gadgets.rpc.register('requestNavigateTo', this.requestNavigateTo);
188 gadgets.IfrGadgetService.inherits(gadgets.GadgetService);
190 gadgets.IfrGadgetService.prototype.setHeight = function(height) {
191 if (height > gadgets.container.maxheight_) {
192 height = gadgets.container.maxheight_;
195 var element = document.getElementById(this.f);
196 if (element) {
197 element.style.height = height + 'px';
201 gadgets.IfrGadgetService.prototype.setTitle = function(title) {
202 var element = document.getElementById(this.f + '_title');
203 if (element) {
204 element.innerHTML = title.replace(/&/g, '&amp;').replace(/</g, '&lt;');
209 * Sets one or more user preferences
210 * @param {String} editToken
211 * @param {String} name Name of user preference
212 * @param {String} value Value of user preference
213 * More names and values may follow
215 gadgets.IfrGadgetService.prototype.setUserPref = function(editToken, name,
216 value) {
217 var id = gadgets.container.gadgetService.getGadgetIdFromModuleId(this.f);
218 var gadget = gadgets.container.getGadget(id);
219 var prefs = gadget.getUserPrefs() || {};
220 for (var i = 1, j = arguments.length; i < j; i += 2) {
221 prefs[arguments[i]] = arguments[i + 1];
223 gadget.setUserPrefs(prefs);
227 * Navigates the page to a new url based on a gadgets requested view and
228 * parameters.
230 gadgets.IfrGadgetService.prototype.requestNavigateTo = function(view,
231 opt_params) {
232 var id = gadgets.container.gadgetService.getGadgetIdFromModuleId(this.f);
233 var url = gadgets.container.gadgetService.getUrlForView(view);
235 if (opt_params) {
236 var paramStr = gadgets.json.stringify(opt_params);
237 if (paramStr.length > 0) {
238 url += '&appParams=' + encodeURIComponent(paramStr);
242 if (url && document.location.href.indexOf(url) == -1) {
243 document.location.href = url;
248 * This is a silly implementation that will need to be overriden by almost all
249 * real containers.
250 * TODO: Find a better default for this function
252 * @param view The view name to get the url for
254 gadgets.IfrGadgetService.prototype.getUrlForView = function(
255 view) {
256 if (view === 'canvas') {
257 return '/canvas';
258 } else if (view === 'profile') {
259 return '/profile';
260 } else {
261 return null;
265 gadgets.IfrGadgetService.prototype.getGadgetIdFromModuleId = function(
266 moduleId) {
267 // Quick hack to extract the gadget id from module id
268 return parseInt(moduleId.match(/_([0-9]+)$/)[1], 10);
272 // -------------
273 // LayoutManager
276 * Layout manager interface.
277 * @constructor
279 gadgets.LayoutManager = function() {
283 * Gets the HTML element that is the chrome of a gadget into which the content
284 * of the gadget can be rendered.
285 * @param {Object} gadget Gadget instance
286 * @return {Object} HTML element that is the chrome for the given gadget
288 gadgets.LayoutManager.prototype.getGadgetChrome = function(gadget) {
289 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
292 // -------------------
293 // StaticLayoutManager
296 * Static layout manager where gadget ids have a 1:1 mapping to chrome ids.
297 * @constructor
299 gadgets.StaticLayoutManager = function() {
300 gadgets.LayoutManager.call(this);
303 gadgets.StaticLayoutManager.inherits(gadgets.LayoutManager);
306 * Sets chrome ids, whose indexes are gadget instance ids (starting from 0).
307 * @param {Array} gadgetChromeIds Gadget id to chrome id map
309 gadgets.StaticLayoutManager.prototype.setGadgetChromeIds =
310 function(gadgetChromeIds) {
311 this.gadgetChromeIds_ = gadgetChromeIds;
314 gadgets.StaticLayoutManager.prototype.getGadgetChrome = function(gadget) {
315 var chromeId = this.gadgetChromeIds_[gadget.id];
316 return chromeId ? document.getElementById(chromeId) : null;
320 // ----------------------
321 // FloatLeftLayoutManager
324 * FloatLeft layout manager where gadget ids have a 1:1 mapping to chrome ids.
325 * @constructor
326 * @param {String} layoutRootId Id of the element that is the parent of all
327 * gadgets.
329 gadgets.FloatLeftLayoutManager = function(layoutRootId) {
330 gadgets.LayoutManager.call(this);
331 this.layoutRootId_ = layoutRootId;
334 gadgets.FloatLeftLayoutManager.inherits(gadgets.LayoutManager);
336 gadgets.FloatLeftLayoutManager.prototype.getGadgetChrome =
337 function(gadget) {
338 var layoutRoot = document.getElementById(this.layoutRootId_);
339 if (layoutRoot) {
340 var chrome = document.createElement('div');
341 chrome.className = 'gadgets-gadget-chrome';
342 chrome.style.cssFloat = 'left';
343 layoutRoot.appendChild(chrome);
344 return chrome;
345 } else {
346 return null;
351 // ------
352 // Gadget
355 * Creates a new instance of gadget. Optional parameters are set as instance
356 * variables.
357 * @constructor
358 * @param {Object} params Parameters to set on gadget. Common parameters:
359 * "specUrl": URL to gadget specification
360 * "private": Whether gadget spec is accessible only privately, which means
361 * browser can load it but not gadget server
362 * "spec": Gadget Specification in XML
363 * "viewParams": a javascript object containing attribute value pairs
364 * for this gadgets
365 * "secureToken": an encoded token that is passed on the URL hash
366 * "hashData": Query-string like data that will be added to the
367 * hash portion of the URL.
368 * "specVersion": a hash value used to add a v= param to allow for better caching
369 * "title": the default title to use for the title bar.
370 * "height": height of the gadget
371 * "width": width of the gadget
372 * "debug": send debug=1 to the gadget server, gets us uncompressed
373 * javascript
375 gadgets.Gadget = function(params) {
376 this.userPrefs_ = {};
378 if (params) {
379 for (var name in params) if (params.hasOwnProperty(name)) {
380 this[name] = params[name];
383 if (!this.secureToken) {
384 // Assume that the default security token implementation is
385 // in use on the server.
386 this.secureToken = 'john.doe:john.doe:appid:cont:url:0:default';
390 gadgets.Gadget.prototype.getUserPrefs = function() {
391 return this.userPrefs_;
394 gadgets.Gadget.prototype.setUserPrefs = function(userPrefs) {
395 this.userPrefs_ = userPrefs;
396 gadgets.container.userPrefStore.savePrefs(this);
399 gadgets.Gadget.prototype.getUserPref = function(name) {
400 return this.userPrefs_[name];
403 gadgets.Gadget.prototype.setUserPref = function(name, value) {
404 this.userPrefs_[name] = value;
405 gadgets.container.userPrefStore.savePrefs(this);
408 gadgets.Gadget.prototype.render = function(chrome) {
409 if (chrome) {
410 var gadget = this;
411 this.getContent(function(content) {
412 chrome.innerHTML = content;
413 window.frames[gadget.getIframeId()].location = gadget.getIframeUrl();
418 gadgets.Gadget.prototype.getContent = function(continuation) {
419 gadgets.callAsyncAndJoin([
420 this.getTitleBarContent, this.getUserPrefsDialogContent,
421 this.getMainContent], function(results) {
422 continuation(results.join(''));
423 }, this);
427 * Gets title bar content asynchronously or synchronously.
428 * @param {Function} continuation Function that handles title bar content as
429 * the one and only argument
431 gadgets.Gadget.prototype.getTitleBarContent = function(continuation) {
432 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
436 * Gets user preferences dialog content asynchronously or synchronously.
437 * @param {Function} continuation Function that handles user preferences
438 * content as the one and only argument
440 gadgets.Gadget.prototype.getUserPrefsDialogContent = function(continuation) {
441 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
445 * Gets gadget content asynchronously or synchronously.
446 * @param {Function} continuation Function that handles gadget content as
447 * the one and only argument
449 gadgets.Gadget.prototype.getMainContent = function(continuation) {
450 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
454 * Gets additional parameters to append to the iframe url
455 * Override this method if you need any custom params.
457 gadgets.Gadget.prototype.getAdditionalParams = function() {
458 return '';
462 // ---------
463 // IfrGadget
465 gadgets.IfrGadget = function(opt_params) {
466 gadgets.Gadget.call(this, opt_params);
467 this.serverBase_ = '../../'; // default gadget server
470 gadgets.IfrGadget.inherits(gadgets.Gadget);
472 gadgets.IfrGadget.prototype.GADGET_IFRAME_PREFIX_ = 'remote_iframe_';
474 gadgets.IfrGadget.prototype.CONTAINER = 'default';
476 gadgets.IfrGadget.prototype.cssClassGadget = 'gadgets-gadget';
477 gadgets.IfrGadget.prototype.cssClassTitleBar = 'gadgets-gadget-title-bar';
478 gadgets.IfrGadget.prototype.cssClassTitle = 'gadgets-gadget-title';
479 gadgets.IfrGadget.prototype.cssClassTitleButtonBar =
480 'gadgets-gadget-title-button-bar';
481 gadgets.IfrGadget.prototype.cssClassGadgetUserPrefsDialog =
482 'gadgets-gadget-user-prefs-dialog';
483 gadgets.IfrGadget.prototype.cssClassGadgetUserPrefsDialogActionBar =
484 'gadgets-gadget-user-prefs-dialog-action-bar';
485 gadgets.IfrGadget.prototype.cssClassTitleButton = 'gadgets-gadget-title-button';
486 gadgets.IfrGadget.prototype.cssClassGadgetContent = 'gadgets-gadget-content';
487 gadgets.IfrGadget.prototype.rpcToken = (0x7FFFFFFF * Math.random()) | 0;
488 gadgets.IfrGadget.prototype.rpcRelay = 'files/container/rpc_relay.html';
490 gadgets.IfrGadget.prototype.getTitleBarContent = function(continuation) {
491 continuation('<div id="' + this.cssClassTitleBar + '-' + this.id +
492 '" class="' + this.cssClassTitleBar + '"><span id="' +
493 this.getIframeId() + '_title" class="' +
494 this.cssClassTitle + '">' + (this.title ? this.title : 'Title') + '</span> | <span class="' +
495 this.cssClassTitleButtonBar +
496 '"><a href="#" onclick="gadgets.container.getGadget(' + this.id +
497 ').handleOpenUserPrefsDialog();return false;" class="' + this.cssClassTitleButton +
498 '">settings</a> <a href="#" onclick="gadgets.container.getGadget(' +
499 this.id + ').handleToggle();return false;" class="' + this.cssClassTitleButton +
500 '">toggle</a></span></div>');
503 gadgets.IfrGadget.prototype.getUserPrefsDialogContent = function(continuation) {
504 continuation('<div id="' + this.getUserPrefsDialogId() + '" class="' +
505 this.cssClassGadgetUserPrefsDialog + '"></div>');
508 gadgets.IfrGadget.prototype.setServerBase = function(url) {
509 this.serverBase_ = url;
512 gadgets.IfrGadget.prototype.getServerBase = function() {
513 return this.serverBase_;
516 gadgets.IfrGadget.prototype.getMainContent = function(continuation) {
517 var iframeId = this.getIframeId();
518 gadgets.rpc.setRelayUrl(iframeId, this.serverBase_ + this.rpcRelay);
519 gadgets.rpc.setAuthToken(iframeId, this.rpcToken);
520 continuation('<div class="' + this.cssClassGadgetContent + '"><iframe id="' +
521 iframeId + '" name="' + iframeId + '" class="' + this.cssClassGadget +
522 '" src="about:blank' +
523 '" frameborder="no" scrolling="no"' +
524 (this.height ? ' height="' + this.height + '"' : '') +
525 (this.width ? ' width="' + this.width + '"' : '') +
526 '></iframe></div>');
529 gadgets.IfrGadget.prototype.getIframeId = function() {
530 return this.GADGET_IFRAME_PREFIX_ + this.id;
533 gadgets.IfrGadget.prototype.getUserPrefsDialogId = function() {
534 return this.getIframeId() + '_userPrefsDialog';
537 gadgets.IfrGadget.prototype.getIframeUrl = function() {
538 return this.serverBase_ + 'ifr?' +
539 'container=' + this.CONTAINER +
540 '&mid=' + this.id +
541 '&nocache=' + gadgets.container.nocache_ +
542 '&country=' + gadgets.container.country_ +
543 '&lang=' + gadgets.container.language_ +
544 '&view=' + gadgets.container.view_ +
545 (this.specVersion ? '&v=' + this.specVersion : '') +
546 (gadgets.container.parentUrl_ ? '&parent=' + encodeURIComponent(gadgets.container.parentUrl_) : '') +
547 (this.debug ? '&debug=1' : '') +
548 this.getAdditionalParams() +
549 this.getUserPrefsParams() +
550 (this.secureToken ? '&st=' + this.secureToken : '') +
551 '&url=' + encodeURIComponent(this.specUrl) +
552 '#rpctoken=' + this.rpcToken +
553 (this.viewParams ?
554 '&view-params=' + encodeURIComponent(gadgets.json.stringify(this.viewParams)) : '') +
555 (this.hashData ? '&' + this.hashData : '');
558 gadgets.IfrGadget.prototype.getUserPrefsParams = function() {
559 var params = '';
560 if (this.getUserPrefs()) {
561 for(var name in this.getUserPrefs()) {
562 var value = this.getUserPref(name);
563 params += '&up_' + encodeURIComponent(name) + '=' +
564 encodeURIComponent(value);
567 return params;
570 gadgets.IfrGadget.prototype.handleToggle = function() {
571 var gadgetIframe = document.getElementById(this.getIframeId());
572 if (gadgetIframe) {
573 var gadgetContent = gadgetIframe.parentNode;
574 var display = gadgetContent.style.display;
575 gadgetContent.style.display = display ? '' : 'none';
579 gadgets.IfrGadget.prototype.handleOpenUserPrefsDialog = function() {
580 if (this.userPrefsDialogContentLoaded) {
581 this.showUserPrefsDialog();
582 } else {
583 var gadget = this;
584 var igCallbackName = 'ig_callback_' + this.id;
585 window[igCallbackName] = function(userPrefsDialogContent) {
586 gadget.userPrefsDialogContentLoaded = true;
587 gadget.buildUserPrefsDialog(userPrefsDialogContent);
588 gadget.showUserPrefsDialog();
591 var script = document.createElement('script');
592 script.src = 'http://gmodules.com/ig/gadgetsettings?mid=' + this.id +
593 '&output=js' + this.getUserPrefsParams() + '&url=' + this.specUrl;
594 document.body.appendChild(script);
598 gadgets.IfrGadget.prototype.buildUserPrefsDialog = function(content) {
599 var userPrefsDialog = document.getElementById(this.getUserPrefsDialogId());
600 userPrefsDialog.innerHTML = content +
601 '<div class="' + this.cssClassGadgetUserPrefsDialogActionBar +
602 '"><input type="button" value="Save" onclick="gadgets.container.getGadget(' +
603 this.id +').handleSaveUserPrefs()"> <input type="button" value="Cancel" onclick="gadgets.container.getGadget(' +
604 this.id +').handleCancelUserPrefs()"></div>';
605 userPrefsDialog.childNodes[0].style.display = '';
608 gadgets.IfrGadget.prototype.showUserPrefsDialog = function(opt_show) {
609 var userPrefsDialog = document.getElementById(this.getUserPrefsDialogId());
610 userPrefsDialog.style.display = (opt_show || opt_show === undefined)
611 ? '' : 'none';
614 gadgets.IfrGadget.prototype.hideUserPrefsDialog = function() {
615 this.showUserPrefsDialog(false);
618 gadgets.IfrGadget.prototype.handleSaveUserPrefs = function() {
619 this.hideUserPrefsDialog();
621 var prefs = {};
622 var numFields = document.getElementById('m_' + this.id +
623 '_numfields').value;
624 for (var i = 0; i < numFields; i++) {
625 var input = document.getElementById('m_' + this.id + '_' + i);
626 if (input.type != 'hidden') {
627 var userPrefNamePrefix = 'm_' + this.id + '_up_';
628 var userPrefName = input.name.substring(userPrefNamePrefix.length);
629 var userPrefValue = input.value;
630 prefs[userPrefName] = userPrefValue;
634 this.setUserPrefs(prefs);
635 this.refresh();
638 gadgets.IfrGadget.prototype.handleCancelUserPrefs = function() {
639 this.hideUserPrefsDialog();
642 gadgets.IfrGadget.prototype.refresh = function() {
643 var iframeId = this.getIframeId();
644 document.getElementById(iframeId).src = this.getIframeUrl();
648 // ---------
649 // Container
652 * Container interface.
653 * @constructor
655 gadgets.Container = function() {
656 this.gadgets_ = {};
657 this.parentUrl_ = 'http://' + document.location.host;
658 this.country_ = 'ALL';
659 this.language_ = 'ALL';
660 this.view_ = 'default';
661 this.nocache_ = 1;
663 // signed max int
664 this.maxheight_ = 0x7FFFFFFF;
667 gadgets.Container.inherits(gadgets.Extensible);
670 * Known dependencies:
671 * gadgetClass: constructor to create a new gadget instance
672 * userPrefStore: instance of a subclass of gadgets.UserPrefStore
673 * gadgetService: instance of a subclass of gadgets.GadgetService
674 * layoutManager: instance of a subclass of gadgets.LayoutManager
677 gadgets.Container.prototype.gadgetClass = gadgets.Gadget;
679 gadgets.Container.prototype.userPrefStore = new gadgets.DefaultUserPrefStore();
681 gadgets.Container.prototype.gadgetService = new gadgets.GadgetService();
683 gadgets.Container.prototype.layoutManager =
684 new gadgets.StaticLayoutManager();
686 gadgets.Container.prototype.setParentUrl = function(url) {
687 this.parentUrl_ = url;
690 gadgets.Container.prototype.setCountry = function(country) {
691 this.country_ = country;
694 gadgets.Container.prototype.setNoCache = function(nocache) {
695 this.nocache_ = nocache;
698 gadgets.Container.prototype.setLanguage = function(language) {
699 this.language_ = language;
702 gadgets.Container.prototype.setView = function(view) {
703 this.view_ = view;
706 gadgets.Container.prototype.setMaxHeight = function(maxheight) {
707 this.maxheight_ = maxheight;
710 gadgets.Container.prototype.getGadgetKey_ = function(instanceId) {
711 return 'gadget_' + instanceId;
714 gadgets.Container.prototype.getGadget = function(instanceId) {
715 return this.gadgets_[this.getGadgetKey_(instanceId)];
718 gadgets.Container.prototype.createGadget = function(opt_params) {
719 return new this.gadgetClass(opt_params);
722 gadgets.Container.prototype.addGadget = function(gadget) {
723 gadget.id = this.getNextGadgetInstanceId();
724 gadget.setUserPrefs(this.userPrefStore.getPrefs(gadget));
725 this.gadgets_[this.getGadgetKey_(gadget.id)] = gadget;
728 gadgets.Container.prototype.addGadgets = function(gadgets) {
729 for (var i = 0; i < gadgets.length; i++) {
730 this.addGadget(gadgets[i]);
735 * Renders all gadgets in the container.
737 gadgets.Container.prototype.renderGadgets = function() {
738 for (var key in this.gadgets_) {
739 this.renderGadget(this.gadgets_[key]);
744 * Renders a gadget. Gadgets are rendered inside their chrome element.
745 * @param {Object} gadget Gadget object
747 gadgets.Container.prototype.renderGadget = function(gadget) {
748 throw Error(gadgets.error.SUBCLASS_RESPONSIBILITY);
751 gadgets.Container.prototype.nextGadgetInstanceId_ = 0;
753 gadgets.Container.prototype.getNextGadgetInstanceId = function() {
754 return this.nextGadgetInstanceId_++;
758 * Refresh all the gadgets in the container.
760 gadgets.Container.prototype.refreshGadgets = function() {
761 for (var key in this.gadgets_) {
762 this.gadgets_[key].refresh();
767 // ------------
768 // IfrContainer
771 * Container that renders gadget using ifr.
772 * @constructor
774 gadgets.IfrContainer = function() {
775 gadgets.Container.call(this);
778 gadgets.IfrContainer.inherits(gadgets.Container);
780 gadgets.IfrContainer.prototype.gadgetClass = gadgets.IfrGadget;
782 gadgets.IfrContainer.prototype.gadgetService = new gadgets.IfrGadgetService();
784 gadgets.IfrContainer.prototype.setParentUrl = function(url) {
785 if (!url.match(/^http[s]?:\/\//)) {
786 url = document.location.href.match(/^[^?#]+\//)[0] + url;
789 this.parentUrl_ = url;
793 * Renders a gadget using ifr.
794 * @param {Object} gadget Gadget object
796 gadgets.IfrContainer.prototype.renderGadget = function(gadget) {
797 var chrome = this.layoutManager.getGadgetChrome(gadget);
798 gadget.render(chrome);
802 * Default container.
804 gadgets.container = new gadgets.IfrContainer();