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  * @overview
 26  * This file defines the portlet.
 27  */
 28 
 29 /**
 30  * @class
 31  * This class provides the implementation for portlet for use in the portal application.
 32  * 
 33  * @param	{ZmList}	list	the list that contains this item (may be <code>null</code>)
 34  * @param	{String}	id		the portlet id
 35  * @param	{Object}	def		the portlet definition
 36  *
 37  * @extends	ZmItem
 38  * 
 39  * @see		ZmPortalApp
 40  */
 41 ZmPortlet = function(list, id, def) {
 42     ZmItem.call(this, ZmItem.PORTLET, id, list);
 43 
 44     // save zimlet
 45     var zimletMgr = appCtxt.getZimletMgr();
 46     this.zimletName = def.zimlet;
 47     this.zimletCtxt = zimletMgr.getZimletsHash()[this.zimletName];
 48     this.zimlet = this.zimletCtxt && this.zimletCtxt.handlerObject;
 49 
 50     // save data
 51 	this.global = /^true|on|yes$/i.test(def.global);
 52     this.icon = def.icon;
 53     this.title = def.title;
 54     if (this.title) {
 55         this.title = this.zimletCtxt ? this.zimletCtxt.processMessage(def.title) : def.zimlet;
 56     }
 57     var portlet = this.zimletCtxt && this.zimletCtxt.portlet;
 58     this.actionUrl = portlet && portlet.actionUrl;
 59 
 60     // merge default and specified properties
 61     this.properties = {};
 62     var defaultProps = portlet && portlet.portletProperties;
 63     for (var i in defaultProps) {
 64         var prop = defaultProps[i];
 65         this.properties[prop.name] = prop.value;
 66     }
 67     if (def.properties) {
 68         for (var i = 0; i < def.properties.length; i++) {
 69             var prop = def.properties[i];
 70             this.properties[prop.name] = prop._content;
 71         }
 72     }
 73 
 74 	// string replacement
 75 	if (this.zimletCtxt) {
 76 		for (var pname in this.properties) {
 77 			this.properties[pname] = this.zimletCtxt.replaceObj(ZmZimletContext.RE_SCAN_APP, this.properties[pname], ZmZimletContext.APP);
 78 			// TODO: replace msg,obj,etc...
 79 		}
 80 	}
 81 
 82     // setup refresh interval
 83     if (this.actionUrl) {
 84         this.setRefreshInterval(this.actionUrl.refresh);
 85     }
 86 }
 87 ZmPortlet.prototype = new ZmItem;
 88 ZmPortlet.prototype.constructor = ZmPortlet;
 89 
 90 ZmPortlet.prototype.toString = function() { return "ZmPortlet"; }
 91 
 92 //
 93 // Data
 94 //
 95 
 96 /**
 97  * The view associated to this portlet. Type is ZmPortletView.
 98  *
 99  * @private
100  */
101 ZmPortlet.prototype.view;
102 
103 /**
104  * @private
105  */
106 ZmPortlet.prototype._refreshActionId = -1;
107 
108 //
109 // Public methods
110 //
111 
112 /**
113  * Refreshes the portlet.
114  * 
115  */
116 ZmPortlet.prototype.refresh = function() {
117     if (this.view) {
118         this._refreshTime = new Date().getTime();
119         if (this.actionUrl) {
120             this.view.setContentUrl(this.actionUrl.target);
121         }
122         else if (this.zimlet instanceof ZmZimletBase) {
123             this.zimlet.portletRefreshed(this);
124         }
125         else if (this.zimlet) {
126             var text = AjxMessageFormat.format(ZmMsg.zimletNotLoaded, this.zimletName);
127             this.setContent(text);
128         }
129         else {
130             var text = AjxMessageFormat.format(ZmMsg.zimletUnknown, this.zimletName);
131             this.setContent(text);
132         }
133     }
134 };
135 
136 /**
137  * Sets the refresh interval.
138  * 
139  * @param	{int}		interval		the refresh interval (in milliseconds)
140  */
141 ZmPortlet.prototype.setRefreshInterval = function(interval) {
142     if (this._refreshActionId != -1) {
143         clearInterval(this._refreshActionId);
144         this._refreshActionId = -1;
145     }
146     this._refreshInterval = interval;
147     if (interval) {
148         if (!this._refreshAction) {
149             this._refreshAction = AjxCallback.simpleClosure(this.refresh, this);
150         }
151         this._refreshActionId = setInterval(this._refreshAction, interval);
152     }
153 };
154 
155 /**
156  * Sets the content.
157  * 
158  * @param	{String}	content		the content
159  */
160 ZmPortlet.prototype.setContent = function(content) {
161     if (this.view) {
162         this.view.setContent(content);
163     }
164     else {
165         DBG.println("no view to set content ("+this.id+")");
166     }
167 };
168 
169 /**
170  * Sets the content url.
171  * 
172  * @param	{String}	url		the content url
173  */
174 ZmPortlet.prototype.setContentUrl = function(url) {
175     if (this.view) {
176         this.view.setContentUrl(url);
177     }
178     else {
179         DBG.println("no view to set content url ("+this.id+")");
180     }
181 };
182 
183 /**
184  * Sets the portlet to "paused".
185  * 
186  * @param	{Boolean}	paused		if <code>true</code>, pause the portlet
187  */
188 ZmPortlet.prototype.setPaused = function(paused) {
189     if (this._refreshActionId != -1 && paused) {
190         this._pauseTime = new Date().getTime();
191         clearInterval(this._refreshActionId);
192         this._refreshActionId = -1;
193     }
194     else if (this._refreshInterval && !paused) {
195         var delta = this._refreshInterval - (this._pauseTime - this._refreshTime);
196         var delay = delta < this._refreshInterval ? delta : 0;
197         var resumeAction = AjxCallback.simpleClosure(this._resumeRefresh, this);
198         setTimeout(resumeAction, delay);
199     }
200 };
201 
202 //
203 // Protected methods
204 //
205 
206 /**
207  * @private
208  */
209 ZmPortlet.prototype._resumeRefresh = function() {
210     this.refresh();
211     this._refreshActionId = setInterval(this._refreshAction, this._refreshInterval);
212 };