1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2007, 2009, 2010, 2013, 2014, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2007, 2009, 2010, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * Creates the portlet manager.
 26  * @class
 27  * This class represents the portlet manager.
 28  * 
 29  * @see		ZmPortalApp
 30  * @see		ZmPortlet
 31  */
 32 ZmPortletMgr = function() {
 33     this._portlets = {};
 34     this._loadedZimlets = {};
 35     this._delayedPortlets = {};
 36 };
 37 
 38 //
 39 // Public methods
 40 //
 41 
 42 /**
 43  * Creates the portlets.
 44  * 
 45  * @param	{Boolean}	global			if <code>true</code>, create global portlets
 46  * @param	{Object}	manifest		the portal manifest
 47  */
 48 ZmPortletMgr.prototype.createPortlets = function(global, manifest) {
 49 	global = global != null ? global : false;
 50 	var portletsCreated = [];
 51     manifest = manifest || appCtxt.getApp(ZmApp.PORTAL).getManifest();
 52     if (manifest) {
 53         var portalDef = manifest.portal;
 54         var portletDefs = portalDef && portalDef.portlets;
 55         if (portletDefs) {
 56             for (var i = 0; i < portletDefs.length; i++) {
 57                 var portletDef = portletDefs[i];
 58 				var portletGlobal = portletDef.global == "true";
 59 				if (portletGlobal != global) continue;
 60                 
 61                 var id = portletDef.panel && portletDef.panel.id;
 62                 if (id && !this._portlets[id] && document.getElementById(id)) {
 63                     this.createPortlet(id, portletDef);
 64                     portletsCreated.push(id);
 65                 }
 66             }
 67         }
 68     }
 69     return portletsCreated;
 70 };
 71 
 72 /**
 73  * Creates the portlet.
 74  * 
 75  * @param	{String}	id		the portlet id
 76  * @param	{Object}	portletDef		the portlet definition
 77  * 
 78  * @return	{ZmPortlet}	the newly created portlet
 79  */
 80 ZmPortletMgr.prototype.createPortlet = function(id, portletDef) {
 81     // create portlet
 82     var portlet = new ZmPortlet(null, id, portletDef);
 83     this._portlets[id] = portlet;
 84 
 85     // notify portlet creation or add to list to notify later
 86 	var name = portlet.zimletName;
 87 	if (this._loadedZimlets[name]) {
 88 		this._portletCreated(portlet);
 89 	}
 90 	else if (name) {
 91 		if (!this._delayedPortlets[name]) {
 92 			this._delayedPortlets[name] = [];
 93 		}
 94 		this._delayedPortlets[name].push(portlet);
 95 	}
 96 
 97     return portlet;
 98 };
 99 
100 /**
101  * Gets the portlets.
102  * 
103  * @return	{Array}		an array of {@link ZmPortlet} objects
104  */
105 ZmPortletMgr.prototype.getPortlets = function() {
106     return this._portlets;
107 };
108 
109 /**
110  * Gets the portlet by id.
111  * 
112  * @param	{String}	id		the portlet id
113  * @return	{ZmPortlet}	the portlet
114  */
115 ZmPortletMgr.prototype.getPortletById = function(id) {
116     return this._portlets[id];
117 };
118 
119 /**
120  * This method is called by ZmZimletContext after the source code for
121  * the zimlet is loaded.
122  * 
123  * @private
124  */
125 ZmPortletMgr.prototype.zimletLoaded = function(zimletCtxt) {
126     this._loadedZimlets[zimletCtxt.name] = true;
127 
128     var delayedPortlets = this._delayedPortlets[zimletCtxt.name];
129     if (delayedPortlets) {
130         for (var i = 0; i < delayedPortlets.length; i++) {
131             var portlet = delayedPortlets[i];
132             this._portletCreated(portlet, zimletCtxt);
133         }
134     }
135     delete this._delayedPortlets[zimletCtxt.name];
136 };
137 
138 /**
139  * This method is called after all of the zimlets have been loaded. It is
140  * a way for the portlet manager to know that there are no more zimlets
141  * expected.
142  * 
143  * @private
144  */
145 ZmPortletMgr.prototype.allZimletsLoaded = function() {
146 	for (var name in this._portlets) {
147 		var portlet = this._portlets[name];
148 		if (!this._loadedZimlets[portlet.zimletName]) {
149 			// NOTE: We don't call setContent because there is no view object
150 			//       if no zimlet code was loaded.
151 			var el = document.getElementById(portlet.id);
152 			if (el) {
153 				el.innerHTML = "";
154 			}
155 		}
156 	}
157 };
158 
159 //
160 // Protected methods
161 //
162 
163 ZmPortletMgr.prototype._portletCreated = function(portlet, zimletCtxt) {
164     // get zimlet context, if needed
165     if (!zimletCtxt) {
166         zimletCtxt = appCtxt.getZimletMgr().getZimletsHash()[portlet.zimletName];
167     }
168 
169     // create view
170     var parentEl = document.getElementById(portlet.id);
171     var view = new ZmPortletView(parentEl, portlet);
172 
173     // call portlet handler
174     var handler = zimletCtxt.handlerObject;
175     portlet.zimlet = handler;
176     if (handler) {
177         handler.portletCreated(portlet);
178     }
179 };