1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 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) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * @overview 26 */ 27 28 /** 29 * Creates a dialog for choosing a tag. 30 * @class 31 * This class presents the user with their list of tags in a tree view so that they 32 * can choose one. There is a text input that can be used to filter the list. 33 * 34 * @param {DwtControl} parent the parent 35 * @param {String} className the class name 36 * 37 * @extends ZmDialog 38 */ 39 ZmPickTagDialog = function(parent, className) { 40 41 var newButton = new DwtDialog_ButtonDescriptor(ZmPickTagDialog.NEW_BUTTON, ZmMsg._new, DwtDialog.ALIGN_LEFT); 42 var params = {parent:parent, className:className, title:ZmMsg.pickATag, extraButtons:[newButton], id: "ZmPickTagDialog"}; 43 ZmDialog.call(this, params); 44 45 this._createControls(); 46 this._setNameField(this._inputDivId); 47 this._tagTreeChangeListener = new AjxListener(this, this._handleTagTreeChange); 48 appCtxt.getTagTree().addChangeListener(this._tagTreeChangeListener); 49 this.registerCallback(ZmPickTagDialog.NEW_BUTTON, this._showNewDialog, this); 50 this._creatingTag = false; 51 this._treeViewListener = new AjxListener(this, this._treeViewSelectionListener); 52 this._lastVal = ""; 53 }; 54 55 ZmPickTagDialog.prototype = new ZmDialog; 56 ZmPickTagDialog.prototype.constructor = ZmPickTagDialog; 57 58 ZmPickTagDialog.NEW_BUTTON = DwtDialog.LAST_BUTTON + 1; 59 60 ZmPickTagDialog.prototype.toString = 61 function() { 62 return "ZmPickTagDialog"; 63 }; 64 65 /** 66 * Pops-up the dialog. 67 * 68 * @param {Hash} params a hash of parameters 69 * @param {ZmAccount} params.account the account 70 */ 71 ZmPickTagDialog.prototype.popup = 72 function(params) { 73 74 if (appCtxt.isChildWindow) { 75 return; //disable for now. 76 } 77 78 params = params || {}; 79 this._account = params.account; 80 81 if (appCtxt.multiAccounts && params.account) { 82 appCtxt.getTagTree().removeChangeListener(this._tagTreeChangeListener); 83 appCtxt.getTagTree(params.account).addChangeListener(this._tagTreeChangeListener); 84 } 85 86 // all this is done here instead of in the constructor due to multi-account issues 87 var overviewId = (appCtxt.multiAccounts && params.account) 88 ? ([this.toString(), "-", params.account.name].join("")) : this.toString(); 89 90 var ovParams = { 91 overviewId: overviewId, 92 treeIds: [ZmOrganizer.TAG], 93 fieldId: this._tagTreeDivId, 94 account: params.account 95 }; 96 this._setOverview(ovParams, true); 97 this._tagTreeView = this._getOverview().getTreeView(ZmOrganizer.TAG); 98 this._tagTreeView.removeSelectionListener(this._treeViewListener); 99 this._tagTreeView.addSelectionListener(this._treeViewListener); 100 var rootId = ZmOrganizer.getSystemId(ZmOrganizer.ID_ROOT); 101 var root = this._tagTreeView.getTreeItemById(rootId); 102 if (root) { 103 root.enableSelection(false); 104 } 105 106 this._loadTags(); // item list for this account's tree view will be cached after the first time 107 this._resetTreeView(); 108 this._focusElement = this._inputField; 109 this._inputField.setValue(""); 110 var tags = appCtxt.getTagTree(this._account).asList(); 111 if (tags.length == 1) { 112 this._tagTreeView.setSelected(tags[0], true, true); 113 } 114 this.setButtonEnabled(DwtDialog.OK_BUTTON, this._tagTreeView.getSelected()); 115 116 ZmDialog.prototype.popup.apply(this, arguments); 117 }; 118 119 ZmPickTagDialog.prototype._contentHtml = 120 function() { 121 this._tagTreeDivId = this._htmlElId + "_tagTreeDivId"; 122 this._inputDivId = this._htmlElId + "_inputDivId"; 123 124 return AjxTemplate.expand("share.Widgets#ZmPickTagDialog", {id:this._htmlElId}); 125 }; 126 127 ZmPickTagDialog.prototype._createControls = 128 function() { 129 this._inputField = new DwtInputField({parent: this}); 130 document.getElementById(this._inputDivId).appendChild(this._inputField.getHtmlElement()); 131 this._inputField.addListener(DwtEvent.ONKEYUP, new AjxListener(this, this._handleKeyUp)); 132 }; 133 134 ZmPickTagDialog.prototype._showNewDialog = 135 function() { 136 var dialog = appCtxt.getNewTagDialog(); 137 dialog.reset(); 138 dialog.registerCallback(DwtDialog.OK_BUTTON, this._newCallback, this); 139 dialog.popup(null, this._account); 140 }; 141 142 ZmPickTagDialog.prototype._newCallback = 143 function(parent, name) { 144 appCtxt.getNewTagDialog().popdown(); 145 var ttc = this._opc.getTreeController(ZmOrganizer.TAG); 146 ttc._doCreate(parent, name); 147 this._creatingTag = true; 148 }; 149 150 ZmPickTagDialog.prototype._loadTags = 151 function() { 152 this._tags = []; 153 var items = this._tagTreeView.getTreeItemList(); 154 for (var i = 0, len = items.length; i < len; i++) { 155 var tag = items[i].getData(Dwt.KEY_OBJECT); 156 if (tag.id != ZmOrganizer.ID_ROOT) { 157 this._tags.push({id:tag.id, name:tag.getName(false, null, true, true).toLowerCase()}); 158 } 159 } 160 }; 161 162 ZmPickTagDialog.prototype._handleTagTreeChange = 163 function(ev) { 164 // TODO - listener for changing tags 165 if (ev.event == ZmEvent.E_CREATE && this._creatingTag) { 166 var tag = ev.getDetail("organizers")[0]; 167 this._tagTreeView.setSelected(tag, true); 168 this._creatingTag = false; 169 } 170 this._loadTags(); 171 }; 172 173 ZmPickTagDialog.prototype._okButtonListener = 174 function(ev) { 175 var selectedTag = this._tagTreeView.getSelected(); 176 if (!selectedTag) { 177 return; 178 } 179 DwtDialog.prototype._buttonListener.call(this, ev, [selectedTag]); 180 }; 181 182 ZmPickTagDialog.prototype._handleKeyUp = 183 function(ev) { 184 185 var key = DwtKeyEvent.getCharCode(ev); 186 if (key === DwtKeyEvent.KEY_TAB) { 187 return; 188 } 189 else if (key === DwtKeyEvent.KEY_ARROW_DOWN) { 190 this._overview[this._curOverviewId].focus(); 191 return; 192 } 193 194 var num = 0, firstMatch; 195 var value = this._inputField.getValue().toLowerCase(); 196 if (value == this._lastVal) { return; } 197 for (var i = 0, len = this._tags.length; i < len; i++) { 198 var tagInfo = this._tags[i]; 199 var ti = this._tagTreeView.getTreeItemById(tagInfo.id); 200 if (ti) { 201 var matches = (tagInfo.name.indexOf(value) == 0); 202 ti.setVisible(matches); 203 if (matches && !firstMatch) { 204 firstMatch = tagInfo.id; 205 } 206 } 207 } 208 209 if (firstMatch) { 210 this._tagTreeView.setSelected(appCtxt.getById(firstMatch), true, true); 211 } 212 else { 213 this._tagTreeView.deselectAll(); 214 } 215 this.setButtonEnabled(DwtDialog.OK_BUTTON, firstMatch); 216 217 this._lastVal = value; 218 }; 219 220 ZmPickTagDialog.prototype._resetTreeView = 221 function() { 222 // make all tree items visible (in case there was prior filtering) 223 for (var i = 0, len = this._tags.length; i < len; i++) { 224 var ti = this._tagTreeView.getTreeItemById(this._tags[i].id); 225 if (ti) { 226 ti.setVisible(true); 227 } 228 } 229 230 this._tagTreeView.getHeaderItem().setExpanded(true, false, true); 231 }; 232 233 ZmPickTagDialog.prototype._treeViewSelectionListener = 234 function(ev) { 235 236 if (ev.detail === DwtTree.ITEM_DESELECTED) { 237 this._inputField.setValue(""); 238 this.setButtonEnabled(DwtDialog.OK_BUTTON, false); 239 return; 240 } 241 242 if (ev.detail !== DwtTree.ITEM_SELECTED && ev.detail !== DwtTree.ITEM_DBL_CLICKED){ 243 return; 244 } 245 246 if (!ev.item.isSelectionEnabled()) { 247 return; 248 } 249 250 var tag = ev.item.getData(Dwt.KEY_OBJECT); 251 if (tag) { 252 this.setButtonEnabled(DwtDialog.OK_BUTTON, true); 253 var value = tag.getName(false, null, true, true); 254 this._lastVal = value.toLowerCase(); 255 this._inputField.setValue(value); 256 if (ev.detail == DwtTree.ITEM_DBL_CLICKED || ev.enter) { 257 this._okButtonListener(); 258 } 259 } 260 }; 261 262 ZmPickTagDialog.prototype._getTabGroupMembers = 263 function() { 264 return [this._inputField, this._overview[this._curOverviewId]]; 265 }; 266 267 ZmPickTagDialog.prototype._enterListener = 268 function(ev) { 269 this._okButtonListener.call(this, ev); 270 }; 271