1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2012, 2013, 2014, 2015, 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) 2006, 2007, 2008, 2009, 2010, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 25 /** 26 * Creates a composite that is populated from a message pattern. 27 * @constructor 28 * @class 29 * This class allows you to create a composite that is populated from 30 * a message pattern and inserts controls at the appropriate places. 31 * For example, say that the message <code>MyMsg.repeatTimes</code> is 32 * defined as the following: 33 * <pre> 34 * MyMsg.repeatTimes = "Repeat: {0} times"; 35 * </pre> 36 * and you want to replace "{0}" with an input field or perhaps a 37 * drop-down menu that enumerates a specific list of choices as part of 38 * the application. To do this, you just create a 39 * {@link DwtMessageComposite} and set the message format, like so: 40 * <pre> 41 * var comp = new DwtMessageComposite(parent); 42 * comp.setFormat(MyMsg.repeatTimes); 43 * </pre> 44 * <p> 45 * The message composite instantiates an {@link AjxMessageFormat} 46 * from the specified message pattern. Then, for each segment it creates 47 * static text or a {@link DwtInputField} for replacement segments 48 * such as "{0}". 49 * <p> 50 * To have more control over the controls that are created and inserted 51 * into the resulting composite, you can pass a callback object to the 52 * method. Each time that a replacement segment is found in the 53 * message pattern, the callback is called with the following parameters: 54 * <ul> 55 * <li>a reference to this message composite object; 56 * <li>a reference to the segment object. 57 * <li>the index at which the segment was found in the message pattern; and 58 * </ul> 59 * The segment object will be an instance of 60 * <code>AjxMessageFormat.MessageSegment</code> and has the following 61 * methods of interest: 62 * <ul> 63 * <li>toSubPattern 64 * <li>getIndex 65 * <li>getType 66 * <li>getStyle 67 * <li>getSegmentFormat 68 * </ul> 69 * <p> 70 * The callback can use this information to determine whether or not 71 * a custom control should be created for the segment. If the callback 72 * returns <code>null</code>, a standard {@link DwtInputField} is 73 * created and inserted. Note: if the callback returns a custom control, 74 * it <em>must</em> be an instance of {@link AjxControl}. 75 * <p> 76 * Here is an example of a message composite created with a callback 77 * that generates a custom control for each replacement segment: 78 * <pre> 79 * function createCustomControl(parent, segment, i) { 80 * return new DwtInputField(parent); 81 * } 82 * 83 * var compParent = ...; 84 * var comp = new DwtMessageComposite(compParent); 85 * 86 * var message = MyMsg.repeatTimes; 87 * var callback = new AjxCallback(null, createCustomControl); 88 * comp.setFormat(message, callback); 89 * </pre> 90 * 91 * @author Andy Clark 92 * 93 * @param {Object} params hash of params: 94 * @param {DwtComposite} parent the parent widget. 95 * @param {string} className the CSS class 96 * @param {constant} posStyle the position style (see {@link DwtControl}) 97 * @param {DwtComposite} parent the parent widget. 98 * @param {string} format the message that defines the text and controls within this composite control 99 * @param {AjxCallback} [controlCallback] the callback to create UI components (only used with format specified) 100 * @param {AjxCallback} [hintsCallback] the callback to provide display hints for the container element of the UI component (only used with format specified) 101 * 102 * @extends DwtComposite 103 */ 104 DwtMessageComposite = function(params) { 105 if (arguments.length == 0) return; 106 107 params = Dwt.getParams(arguments, DwtMessageComposite.PARAMS); 108 109 if (!params.className) { 110 params.className = "DwtMessageComposite"; 111 } 112 113 DwtComposite.call(this, params); 114 115 this._tabGroup = new DwtTabGroup("DwtMessageComposite"); 116 117 if (params.format) { 118 this.setFormat(params.format, 119 params.controlCallback, 120 params.hintsCallback); 121 } 122 } 123 124 DwtMessageComposite.PARAMS = ['parent', 'className', 'posStyle']; 125 126 DwtMessageComposite.prototype = new DwtComposite; 127 DwtMessageComposite.prototype.constructor = DwtMessageComposite; 128 DwtMessageComposite.prototype.isDwtMessageComposite = true; 129 130 DwtMessageComposite.prototype.toString = 131 function() { 132 return "DwtMessageComposite"; 133 } 134 135 // Public methods 136 137 /** 138 * Sets the format. 139 * 140 * @param {string} message the message that defines the text and controls that comprise this composite 141 * @param {AjxCallback} [callback] the callback to create UI components 142 * @param {AjxCallback} [hintsCallback] the callback to provide display hints for the container element of the UI component 143 */ 144 DwtMessageComposite.prototype.setFormat = 145 function(message, callback, hintsCallback) { 146 // create formatter 147 this._formatter = new AjxMessageFormat(message); 148 this._controls = {}; 149 150 // create HTML 151 var id = this._htmlElId; 152 this.getHtmlElement().innerHTML = "<table class='DwtCompositeTable' border='0' cellspacing='0' cellpadding='0'><tr valign='center'></tr></table>"; 153 var row = this.getHtmlElement().firstChild.rows[0]; 154 155 var segments = this._formatter.getSegments(); 156 for (var i = 0; i < segments.length; i++) { 157 var segment = segments[i]; 158 var isMsgSegment = segment instanceof AjxMessageFormat.MessageSegment; 159 160 var cid = [id,i].join("_"); 161 var cell = document.createElement('TD'); 162 163 cell.id = cid; 164 cell.className = 'DwtCompositeCell'; 165 row.appendChild(cell); 166 167 if (isMsgSegment) { 168 cell.className += ' MessageControl' + segment.getIndex(); 169 var control = callback ? callback.run(this, segment, i) : null; 170 if (!control) { 171 control = new DwtInputField({parent:this, parentElement: cell}); 172 } else { 173 control.reparentHtmlElement(cell); 174 } 175 this._tabGroup.addMember(control.getTabGroupMember()); 176 if (hintsCallback) { 177 var hints = hintsCallback.run(this, segment, i); 178 179 AjxUtil.hashUpdate(control.getHtmlElement(), hints, true); 180 } 181 182 var sindex = segment.getIndex(); 183 this._controls[sindex] = this._controls[sindex] || control; 184 } 185 else { 186 control = new DwtText({parent:this, parentElement: cell}); 187 control.setText(segment.toSubPattern()); 188 this._tabGroup.addMember(control); 189 } 190 } 191 }; 192 193 /** 194 * Gets the format. 195 * 196 * @return {string} the format 197 */ 198 DwtMessageComposite.prototype.format = function() { 199 var args = []; 200 for (var sindex in this._controls) { 201 args[sindex] = this._controls[sindex].getValue(); 202 } 203 return this._formatter.format(args); 204 }; 205 206 DwtMessageComposite.prototype.getTabGroupMember = function() { 207 return this._tabGroup; 208 }; 209