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.
20 * @fileoverview Open Gadget Container
23 var gadgets
= gadgets
|| {};
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
) {
33 var logEntry
= document
.createElement('div');
34 logEntry
.className
= 'gadgets-log-entry';
35 logEntry
.innerHTML
= message
;
36 document
.body
.appendChild(logEntry
);
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);
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
55 gadgets
.callAsyncAndJoin = function(functions
, continuation
, opt_this
) {
56 var pending
= functions
.length
;
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
);
77 gadgets
.Extensible = function() {
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
];
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
) {
106 * User preference store interface.
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
);
132 // DefaultUserPrefStore
135 * User preference store implementation.
136 * TODO: Turn this into a real implementation that is production safe
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
) { };
153 * Interface of service provided to gadgets for resizing gadgets,
154 * setting title, etc.
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
);
177 * Base implementation of GadgetService.
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
);
197 element
.style
.height
= height
+ 'px';
201 gadgets
.IfrGadgetService
.prototype.setTitle = function(title
) {
202 var element
= document
.getElementById(this.f
+ '_title');
204 element
.innerHTML
= title
.replace(/&/g, '&').replace(/</g
, '<');
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
,
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
230 gadgets
.IfrGadgetService
.prototype.requestNavigateTo = function(view
,
232 var id
= gadgets
.container
.gadgetService
.getGadgetIdFromModuleId(this.f
);
233 var url
= gadgets
.container
.gadgetService
.getUrlForView(view
);
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
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(
256 if (view
=== 'canvas') {
258 } else if (view
=== 'profile') {
265 gadgets
.IfrGadgetService
.prototype.getGadgetIdFromModuleId = function(
267 // Quick hack to extract the gadget id from module id
268 return parseInt(moduleId
.match(/_([0-9]+)$/)[1], 10);
276 * Layout manager interface.
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.
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.
326 * @param {String} layoutRootId Id of the element that is the parent of all
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
=
338 var layoutRoot
= document
.getElementById(this.layoutRootId_
);
340 var chrome
= document
.createElement('div');
341 chrome
.className
= 'gadgets-gadget-chrome';
342 chrome
.style
.cssFloat
= 'left';
343 layoutRoot
.appendChild(chrome
);
355 * Creates a new instance of gadget. Optional parameters are set as instance
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
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
375 gadgets
.Gadget = function(params
) {
376 this.userPrefs_
= {};
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
) {
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(''));
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() {
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
+ '"' : '') +
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
+
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
+
554 '&view-params=' + encodeURIComponent(gadgets
.json
.stringify(this.viewParams
)) : '') +
555 (this.hashData
? '&' + this.hashData
: '');
558 gadgets
.IfrGadget
.prototype.getUserPrefsParams = function() {
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
);
570 gadgets
.IfrGadget
.prototype.handleToggle = function() {
571 var gadgetIframe
= document
.getElementById(this.getIframeId());
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();
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)
614 gadgets
.IfrGadget
.prototype.hideUserPrefsDialog = function() {
615 this.showUserPrefsDialog(false);
618 gadgets
.IfrGadget
.prototype.handleSaveUserPrefs = function() {
619 this.hideUserPrefsDialog();
622 var numFields
= document
.getElementById('m_' + this.id
+
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
);
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();
652 * Container interface.
655 gadgets
.Container = function() {
657 this.parentUrl_
= 'http://' + document
.location
.host
;
658 this.country_
= 'ALL';
659 this.language_
= 'ALL';
660 this.view_
= 'default';
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
) {
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();
771 * Container that renders gadget using ifr.
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
);
804 gadgets
.container
= new gadgets
.IfrContainer();