1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011, 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) 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  * 
 27  * This file contains the zimlet object handler base class.
 28  * 
 29  */
 30 
 31 /**
 32  * Creates the object handler.
 33  * @class
 34  * This class defines the default implementation for a zimlet object handler.
 35  * <br />
 36  * <br />
 37  * To write a zimlet, see {@link ZmZimletBase}. 
 38  * 
 39  * @param	{string}	typeName	the type name
 40  * @param	{string}	className	the class name
 41  */
 42 ZmObjectHandler = function(typeName, className) {
 43 	if (arguments.length > 0) {
 44 		this.init(typeName, className);
 45 	}
 46 }
 47 
 48 ZmObjectHandler.prototype.constructor = ZmObjectHandler;
 49 ZmObjectHandler.prototype.isZmObjectHandler = true;
 50 
 51 /**
 52  * This method is called by the Zimlet framework to initialize the object.
 53  * 
 54  * @param	{string}	typeName	the type name
 55  * @param	{string}	className	the class name; if <code>null</code>, "Object" will be used
 56  */
 57 ZmObjectHandler.prototype.init =
 58 function(typeName, className) {
 59 	this._typeName = typeName;
 60 	this._className = className ? className : "Object";
 61 	this.name = this.toString();
 62 };
 63 
 64 /**
 65  * Returns a string representation of the object.
 66  * 
 67  * @return		{string}		a string representation of the object
 68  */
 69 ZmObjectHandler.prototype.toString = 
 70 function() {
 71 	// If you can find a cleaner way to get the name of 
 72 	// a sub-class without hard coding each instance
 73 	// in a toString() method feel free to change.
 74 	if(!this._toString) {
 75 		var ctor = "" + this.constructor;
 76 		ctor = ctor.substring(0,ctor.indexOf("("));
 77 		this._toString = ctor.substring("function ".length);
 78 	}
 79 	return this._toString;
 80 };
 81 
 82 ZmObjectHandler.prototype.getEnabled =	function() {
 83 	return true;
 84 };
 85 
 86 
 87 /**
 88  * Gets the type name.
 89  * 
 90  * @return	{string}		the type name
 91  */
 92 ZmObjectHandler.prototype.getTypeName =
 93 function() {
 94 	return this._typeName;
 95 };
 96 
 97 /**
 98  * Gets the class name for a given object.
 99  * 
100  * @param	{Object}		obj			the object
101  * @param	{Object}		context		the content
102  * @param	{string}		spanId		ID of the SPAN
103  *
104  * @return	{string}		the class name
105  */
106 ZmObjectHandler.prototype.getClassName =
107 function(obj, context, spanId) {
108 	return this._className;
109 };
110 
111 /**
112  * Gets the hovered class name for the given object.
113  * 
114  * @param	{Object}		obj			the object
115  * @param	{Object}		context		the content
116  * @param	{string}		spanId		ID of hovered SPAN
117  *
118  * @return	{string}		the hovered class name
119  */
120 ZmObjectHandler.prototype.getHoveredClassName =
121 function(obj, context, spanId) {
122 	var cname = this.getClassName(obj, context, spanId);
123 	if (this._cachedClassNameForHovered !== cname) {
124 		this._cachedClassNameForHovered = cname;
125 		this._classNameHovered = cname + "-" + DwtCssStyle.HOVER;
126 	}
127 	return this._classNameHovered;
128 };
129 
130 /**
131  * Gets the active class name for a given object.
132  * 
133  * @param	{Object}		obj		the object
134  * @param	{Object}		context		the content
135  * @param	{string}		spanId		ID of the SPAN
136  *
137  * @return	{string}		the active class name
138  */
139 ZmObjectHandler.prototype.getActiveClassName =
140 function(obj, context, spanId) {
141 	var cname = this.getClassName(obj, context, spanId);
142 	if (this._cachedClassNameForActive !== cname) {
143 		this._cachedClassNameForActive = cname;
144 		this._classNameActive = cname + "-" + DwtCssStyle.ACTIVE;
145 	}
146 	return this._classNameActive;
147 };
148 
149 /**
150  * @private
151  */
152 ZmObjectHandler.prototype.findObject =
153 function(content, startIndex, objectMgr) {
154 	if (startIndex === 0) {
155 		this._lastMatch = null;
156 		this._noMatch = false;
157 	}
158 	if (this._noMatch) {return null;}
159 	if (this._lastMatch && this._lastMatch.index >= startIndex) {
160 		return this._lastMatch;
161 	}
162 	this._lastMatch = this.match(content, startIndex, objectMgr);
163 	this._noMatch = (this._lastMatch === null);
164 	return this._lastMatch;
165 };
166 
167 
168 /**
169  * This method is used to match content for a zimlet. Zimlet implementations should
170  * override this method. Usage should return a non-null result in the format of
171  * <code>String.match</code> if text on the line matched the handler regular expression.
172  * 
173  * <pre>
174  * var result = handler.match(line);
175  * result[0] // should be matched string
176  * result.index // should be location within line match occurred
177  * </pre>
178  * 
179  * Handlers can also set result.context which will be passed back to
180  * them during the various method calls ({@link #getToolTipText}, etc). Handlers should set
181  * regex.lastIndex to startIndex and then use <code>regex.exec(content)</code>. Handlers should
182  * also use the "g" option when constructing their regex.
183  */
184 ZmObjectHandler.prototype.match =
185 function(content, startIndex) {
186 	return null;
187 };
188 
189 /**
190  * Generates content inside the <code><span></code> tag.
191  * 
192  * @return	{number}	the content index
193  * @private
194  * */
195 ZmObjectHandler.prototype._getHtmlContent =
196 function(html, idx, obj, context, spanId) {
197 	html[idx++] = AjxStringUtil.htmlEncode(obj, true);
198 	return idx;
199 };
200 
201 /**
202  * Generates the <code><span></code> tag.
203  * 
204  * @return	{number}	the content index
205  * @private
206  */
207 ZmObjectHandler.prototype.generateSpan = 
208 function(html, idx, obj, spanId, context, options) {
209 	html[idx++] = "<span class='";
210 	html[idx++] = this.getClassName(obj);
211 	html[idx++] = "' role='link' id='";
212 	html[idx++] = spanId;
213 	html[idx++] = "'>";
214 	idx = this._getHtmlContent(html, idx, obj, context, spanId, options);
215 	html[idx++] = "</span>";
216 	return idx;
217 };
218 
219 /**
220  * Checks if the handler has tool tip text.
221  * 
222  * @param		{Object}	obj			the object
223  * @param		{Object}	context		the context
224  * @return		<code>true</code> if the handler has tool tip text; <code>false</code> otherwise
225  */
226 ZmObjectHandler.prototype.hasToolTipText =
227 function(obj, context) {
228 	return true;
229 };
230 
231 /**
232  * Gets the handler tool tip text.
233  * 
234  * @param		{Object}	obj			the object
235  * @param		{Object}	context		the context
236  * @return		{string}	the handler has tool tip text
237  */
238 ZmObjectHandler.prototype.getToolTipText =
239 function(obj, context) {
240 	return AjxStringUtil.htmlEncode(obj);
241 };
242 
243 /**
244  * Populates the handler tool tip text.
245  * 
246  * @param		{Object}	obj			the object
247  * @param		{Object}	context		the context
248  */
249 ZmObjectHandler.prototype.populateToolTip =
250 function(obj, context) {
251 };
252 
253 /**
254  * Gets the action menu.
255  * 
256  * @param		{Object}	obj			the object
257  * @param		{string}	span		the span element
258  * @param		{Object}	context		the context
259  * @return		{ZmActionMenu}	the action menu
260  * 
261  * @private
262  */
263 ZmObjectHandler.prototype.getActionMenu =
264 function(obj, span, context) {
265 	return null;
266 };
267 
268 /**
269  * This method is called by the Zimlet framework when the object is selected.
270  * 
271  * @param		{Object}	obj			the object
272  * @param		{string}	span		the span element
273  * @param		{Object}	ev			the event
274  * @param		{Object}	context		the context
275  * @see		#clicked
276  */
277 ZmObjectHandler.prototype.selected =
278 function(obj, span, ev, context) {
279 	return this.clicked(span, obj, context, ev);
280 };
281 
282 /**
283  * This method is called by the Zimlet framework when the object is clicked.
284  * 
285  * @param		{Object}	obj			the object
286  * @param		{string}	span		the span element
287  * @param		{Object}	ev			the event
288  * @param		{Object}	context		the context
289  */
290 ZmObjectHandler.prototype.clicked =
291 function(span, obj, context, ev) {
292 };
293 
294 /**
295  * This method is called when the object is hovered-over.
296  * 
297  * @private
298  */
299 ZmObjectHandler.prototype.hoverOver = function(object, context, x, y) {
300 
301 	var tooltip = this.getToolTipText(object, context) || '',
302 		content, callback;
303 
304 	if (typeof(tooltip) === "string") {
305 		content = tooltip;
306 	}
307 	else if (tooltip.isAjxCallback || AjxUtil.isFunction(tooltip)) {
308 		callback = tooltip;
309 	}
310 	else if (typeof(tooltip) === "object") {
311 		content = tooltip.content;
312 		callback = tooltip.callback;
313 	}
314 
315 	if (!content && callback && tooltip.loading) {
316 		content = AjxMsg.loading;
317 	}
318 
319 	if (content) {
320 		this._showTooltip(object, context, x, y, content);
321 	}
322 
323 	if (callback) {
324 		var callback1 = new AjxCallback(this, this._showTooltip, [ object, context, x, y ]);
325 		AjxTimedAction.scheduleAction(new AjxTimedAction(null, function() {
326 			callback.run(callback1);
327 		}), 0);
328 	}
329 };
330 
331 ZmObjectHandler.prototype._showTooltip = function(object, context, x, y, content) {
332 	var shell = DwtShell.getShell(window);
333 	var tooltip = shell.getToolTip();
334 	tooltip.setContent(content);
335 	tooltip.popup(x, y);
336 	// TODO: call below is odd; not sure if it's used much, appears to be for two-step tooltips (eg a map)
337 	this.populateToolTip(object, context);
338 };
339 
340 /**
341  * This method is called when the handler is hovered-out.
342  * 
343  * @private
344  */
345 ZmObjectHandler.prototype.hoverOut = function(object, context) {
346 	var shell = DwtShell.getShell(window);
347 	var tooltip = shell.getToolTip();
348 	tooltip.popdown();
349 };
350