1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2004, 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) 2004, 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 * @class 26 * This class represent a search toolbar. The components are some set of: an input field, 27 * a search button, a save button, and a button to choose what type of item to search for. 28 * 29 * @param {hash} params a hash of parameters: 30 * @param {DwtComposite} parent the parent widget 31 * @param {string} id an explicit ID to use for the control's HTML element 32 * 33 * @extends DwtComposite 34 */ 35 ZmSearchToolBar = function(params) { 36 37 if (arguments.length == 0) { return; } 38 39 params.className = params.className || "ZmSearchToolbar"; 40 this._button = {}; 41 DwtToolBar.apply(this, arguments); 42 43 this._origin = ZmId.SEARCH; 44 this._searchMenu = null; 45 }; 46 47 ZmSearchToolBar.prototype = new DwtToolBar; 48 ZmSearchToolBar.prototype.constructor = ZmSearchToolBar; 49 50 ZmSearchToolBar.prototype.isZmSearchToolBar = true; 51 ZmSearchToolBar.prototype.toString = function() { return "ZmSearchToolBar"; }; 52 ZmSearchToolBar.prototype.role = 'toolbar'; 53 54 // Consts 55 56 57 ZmSearchToolBar.TYPES_BUTTON = "TYPES"; 58 ZmSearchToolBar.SEARCH_BUTTON = "SEARCH"; 59 ZmSearchToolBar.SAVE_BUTTON = "SAVE"; 60 ZmSearchToolBar.SEARCH_MENU_BUTTON = ZmSearchToolBar.TYPES_BUTTON; // back-compatibility 61 62 ZmSearchToolBar.MENU_ITEMS = []; // list of menu items 63 ZmSearchToolBar.SETTING = {}; // required setting for menu item to appear 64 ZmSearchToolBar.MSG_KEY = {}; // text for menu item 65 ZmSearchToolBar.TT_MSG_KEY = {}; // tooltip text for menu item 66 ZmSearchToolBar.ICON = {}; // icon for menu item 67 ZmSearchToolBar.SHARE_ICON = {}; // icon for shared menu item 68 ZmSearchToolBar.ID = {}; // ID for menu item 69 ZmSearchToolBar.DISABLE_OFFLINE = {}; // Disable when offline detected 70 71 72 // Public static methods 73 74 /** 75 * Defines a menu item to add when the types menu is created. Static so that it can be called before the 76 * toolbar has been created. 77 * 78 * @param {string} id ID of menu item 79 * @param {hash} params menu item properties 80 */ 81 ZmSearchToolBar.addMenuItem = 82 function(id, params) { 83 84 if (params.msgKey) { ZmSearchToolBar.MSG_KEY[id] = params.msgKey; } 85 if (params.tooltipKey) { ZmSearchToolBar.TT_MSG_KEY[id] = params.tooltipKey; } 86 if (params.icon) { ZmSearchToolBar.ICON[id] = params.icon; } 87 if (params.shareIcon) { ZmSearchToolBar.SHARE_ICON[id] = params.shareIcon; } 88 if (params.setting) { ZmSearchToolBar.SETTING[id] = params.setting; } 89 if (params.id) { ZmSearchToolBar.ID[id] = params.id; } 90 if (params.disableOffline) { ZmSearchToolBar.DISABLE_OFFLINE[id] = params.disableOffline; } 91 92 if (params.index == null || params.index < 0 || params.index >= ZmSearchToolBar.MENU_ITEMS.length) { 93 ZmSearchToolBar.MENU_ITEMS.push(id); 94 } else { 95 ZmSearchToolBar.MENU_ITEMS.splice(params.index, 0, id); 96 } 97 }; 98 99 100 // Public methods 101 102 /** 103 * Removes a menu item from the types menu. 104 * 105 * @param {string} id ID of menu item 106 */ 107 ZmSearchToolBar.prototype.removeMenuItem = 108 function(id) { 109 110 var menu = this._searchMenu; 111 if (menu) { 112 var mi = menu.getItemById(ZmOperation.MENUITEM_ID, id); 113 if (mi) { 114 menu.removeChild(mi); 115 mi.dispose(); 116 } 117 this._cleanupSeparators(menu); 118 } 119 }; 120 121 // Remove unneeded separators 122 ZmSearchToolBar.prototype._cleanupSeparators = 123 function(menu) { 124 125 var button = this._button[ZmSearchToolBar.TYPES_BUTTON]; 126 menu = menu || (button && button.getMenu()); 127 if (!menu) { return; } 128 129 var items = menu.getItems(); 130 var toRemove = []; 131 for (var i = 0; i < items.length; i++) { 132 var mi = items[i]; 133 if (mi.isSeparator() && (i == 0 || i == items.length - 1 || items[i - 1].isSeparator())) { 134 toRemove.push(mi); 135 } 136 } 137 for (var i = 0; i < toRemove.length; i++) { 138 var mi = toRemove[i]; 139 menu.removeChild(mi); 140 mi.dispose(); 141 } 142 }; 143 144 ZmSearchToolBar.prototype.getSearchField = 145 function() { 146 return this._searchField.getInputElement(); 147 }; 148 149 // sets up a function to call when Enter has been pressed 150 ZmSearchToolBar.prototype.registerEnterCallback = 151 function(callback) { 152 this._enterCallback = callback; 153 }; 154 155 ZmSearchToolBar.prototype.addSelectionListener = 156 function(buttonId, listener) { 157 var button = this._button[buttonId]; 158 if (button) { 159 button.addSelectionListener(listener); 160 } 161 }; 162 163 ZmSearchToolBar.prototype.getButton = 164 function(buttonId) { 165 return this._button[buttonId]; 166 }; 167 168 ZmSearchToolBar.prototype.getButtons = 169 function() { 170 return AjxUtil.values(this._button); 171 }; 172 173 ZmSearchToolBar.prototype.focus = function(item) { 174 175 if (item) { 176 // focus is being moved via a shortcut (arrow key) 177 return DwtToolBar.prototype.focus.apply(this, arguments); 178 } 179 else if (this._searchField) { 180 this._searchField.focus(); 181 this._searchField.moveCursorToEnd(); 182 return this._searchField; 183 } 184 }; 185 186 ZmSearchToolBar.prototype.blur = 187 function() { 188 if (this._searchField) { 189 this._searchField.blur(); 190 } 191 }; 192 193 ZmSearchToolBar.prototype.setEnabled = 194 function(enable) { 195 if (this._searchField) { 196 this._searchField.setEnabled(enable); 197 } 198 for (var buttonId in this._button) { 199 this._button[buttonId].setEnabled(enable); 200 } 201 }; 202 ZmSearchToolBar.prototype.setSearchFieldValue = 203 function(value) { 204 if (this._searchField && value != this.getSearchFieldValue()) { 205 this._searchField.setValue(value); 206 } 207 }; 208 209 ZmSearchToolBar.prototype.getSearchFieldValue = 210 function() { 211 return this._searchField ? this._searchField.getValue() : null; 212 }; 213 214 215 216 // Private methods 217 218 ZmSearchToolBar.prototype._handleKeyDown = 219 function(ev) { 220 var key = DwtKeyEvent.getCharCode(ev); 221 if (DwtKeyEvent.IS_RETURN[key]) { 222 return this._handleEnterKeyPress(ev); 223 } 224 return true; 225 }; 226 227 ZmSearchToolBar.prototype._handleEnterKeyPress = 228 function(ev) { 229 if (this._enterCallback) { 230 this._enterCallback.run({ 231 ev: ev, 232 zimletEvent: "onKeyPressSearchField", 233 origin: this._origin 234 }); 235 } 236 return false; 237 }; 238 239 /** 240 * Initializes search autocomplete. 241 */ 242 ZmSearchToolBar.prototype.initAutocomplete = 243 function() { 244 if (!this._acList) { 245 this._acList = new ZmAutocompleteListView(this._getAutocompleteParams()); 246 this._acList.handle(this.getSearchField()); 247 } 248 }; 249 250 ZmSearchToolBar.prototype._getAutocompleteParams = 251 function() { 252 var params = { 253 dataClass: new ZmSearchAutocomplete(), 254 matchValue: "matchText", 255 delims: [" ", "\t"], 256 delimCodes: [3, 13, 9], 257 separator: " ", 258 keyDownCallback: this._handleKeyDown.bind(this), 259 contextId: this.toString(), 260 locationCallback: this._getAcLocation.bind(this) 261 }; 262 return params; 263 }; 264 265 ZmSearchToolBar.prototype.getAutocompleteListView = 266 function() { 267 return this._acList; 268 }; 269 270 ZmSearchToolBar.prototype._getAcLocation = 271 function() { 272 var el = this._searchField.getInputElement(); 273 if (!el) { return {}; } 274 275 var elLoc = Dwt.getLocation(el); 276 var elSize = Dwt.getSize(el); 277 var strWidth = AjxStringUtil.getWidth(el.value); 278 if (AjxEnv.isWindows && (AjxEnv.isFirefox || AjxEnv.isSafari || AjxEnv.isChrome) ){ 279 // FF/Win: fudge factor since string is longer in INPUT than when measured in SPAN 280 strWidth = strWidth * 1.2; 281 } 282 var x = elLoc.x + strWidth; 283 var y = elLoc.y + elSize.y; 284 DwtPoint.tmp.set(x, y); 285 return DwtPoint.tmp; 286 }; 287 288 289 290 291 /** 292 * Adds a types button and support for a custom search menu item to a search toolbar 293 * 294 * @param params 295 */ 296 ZmMainSearchToolBar = function(params) { 297 298 if (arguments.length == 0) { return; } 299 300 ZmSearchToolBar.apply(this, arguments); 301 302 this._initialize(); 303 304 // setup "include shared" menu item 305 var miParams = { 306 msgKey: "searchShared", 307 tooltipKey: "searchShared", 308 icon: "Group", 309 setting: ZmSetting.SHARING_ENABLED, 310 id: ZmId.getMenuItemId(ZmId.SEARCH, ZmId.SEARCH_SHARED), 311 disableOffline: true 312 }; 313 ZmSearchToolBar.addMenuItem(ZmId.SEARCH_SHARED, miParams); 314 315 // setup "all accounts" menu item for multi account 316 if (appCtxt.multiAccounts) { 317 var miParams = { 318 msgKey: "searchAllAccounts", 319 icon: "Globe", 320 id: ZmId.getMenuItemId(ZmId.SEARCH, ZmId.SEARCH_ALL_ACCOUNTS) 321 }; 322 ZmSearchToolBar.addMenuItem(ZmId.SEARCH_ALL_ACCOUNTS, miParams); 323 } 324 }; 325 326 ZmMainSearchToolBar.prototype = new ZmSearchToolBar; 327 ZmMainSearchToolBar.prototype.constructor = ZmMainSearchToolBar; 328 329 ZmMainSearchToolBar.prototype.isZmMainSearchToolBar = true; 330 ZmMainSearchToolBar.prototype.toString = function() { return "ZmMainSearchToolBar"; }; 331 332 ZmMainSearchToolBar.CUSTOM_ITEM_ID = "CustomSearchItem"; // custom search menu item key 333 ZmMainSearchToolBar.CUSTOM_BUTTON = "CUSTOM"; // button ID 334 335 ZmMainSearchToolBar.prototype._initialize = function() { 336 337 var isExternalAccount = appCtxt.isExternalAccount(); 338 339 // add "search types" menu 340 var firstItem = ZmSearchToolBar.MENU_ITEMS[0]; 341 var buttonId = ZmId.getButtonId(ZmId.SEARCH, ZmId.SEARCH_MENU); 342 var button = this._button[ZmSearchToolBar.TYPES_BUTTON] = new DwtButton({ 343 parent: this, 344 index: 0, 345 id: buttonId 346 }); 347 button.setImage(ZmSearchToolBar.ICON[firstItem]); 348 button.setToolTipContent(ZmMsg[ZmSearchToolBar.TT_MSG_KEY[firstItem]], true); 349 350 var menu = new AjxCallback(this, this._createSearchMenu); 351 button.setMenu(menu, false, DwtMenuItem.RADIO_STYLE); 352 if (isExternalAccount) { 353 button.setEnabled(false); 354 } 355 356 // add search box 357 var searchBox = this._searchField = new DwtInputField({ 358 parent: this, 359 hint: ZmMsg.searchInput, 360 label: ZmMsg.searchInput, 361 inputId: ZmId.SEARCH_INPUTFIELD 362 }); 363 var inputEl = searchBox.getInputElement(); 364 inputEl.className = "search_input"; 365 this._searchField._showHint(); 366 this._searchField.addListener(DwtEvent.ONFOCUS, this._onInputFocus.bind(this)); 367 this._searchField.addListener(DwtEvent.ONBLUR, this._onInputBlur.bind(this)); 368 if (isExternalAccount) { 369 this._searchField.setEnabled(false); 370 } 371 searchBox.addListener(DwtEvent.ONFOCUS, this._childFocusListener.bind(this)); 372 373 // add search button 374 button = this._button[ZmSearchToolBar.SEARCH_BUTTON] = new DwtButton({ 375 parent: this, 376 className: "ZmSearchButton", 377 id: ZmId.getButtonId(ZmId.SEARCH, ZmId.SEARCH_SEARCH) 378 }); 379 button.setImage("Search2"); 380 button.setToolTipContent(ZmMsg.searchTooltip, true); 381 382 // add save search button if saved-searches enabled 383 if (isExternalAccount) { 384 if (this._button[ZmSearchToolBar.SEARCH_BUTTON]) { 385 this._button[ZmSearchToolBar.SEARCH_BUTTON].setEnabled(false); 386 } 387 } 388 }; 389 390 ZmMainSearchToolBar.prototype._createSearchMenu = 391 function() { 392 393 var menu = this._searchMenu = new DwtMenu({ 394 parent: this._button[ZmSearchToolBar.TYPES_BUTTON], 395 className: "ActionMenu", 396 id: ZmId.getMenuId(ZmId.SEARCH) 397 }); 398 var mi; 399 if (this._customSearchMenuItems) { 400 for (var i = 0; i < this._customSearchMenuItems.length; i++) { 401 var csmi = this._customSearchMenuItems[i]; 402 this._createCustomSearchMenuItem(menu, csmi.icon, csmi.text, csmi.listener); 403 } 404 } 405 var params = { 406 parent: menu, 407 enabled: true, 408 radioGroupId: 0, 409 style: DwtMenuItem.RADIO_STYLE 410 }; 411 for (var i = 0; i < ZmSearchToolBar.MENU_ITEMS.length; i++) { 412 var id = ZmSearchToolBar.MENU_ITEMS[i]; 413 414 // add separator *before* "shared" menu item 415 if (id == ZmId.SEARCH_SHARED) { 416 if (ZmSearchToolBar.MENU_ITEMS.length <= 1) { continue; } 417 mi = new DwtMenuItem({parent:menu, style:DwtMenuItem.SEPARATOR_STYLE}); 418 } 419 420 var setting = ZmSearchToolBar.SETTING[id]; 421 if (setting && !appCtxt.get(setting)) { continue; } 422 423 var isCheckStyle = (id == ZmId.SEARCH_SHARED || id == ZmId.SEARCH_ALL_ACCOUNTS); 424 if (isCheckStyle) { 425 params.style = DwtMenuItem.CHECK_STYLE; 426 } 427 params.style = (id == ZmId.SEARCH_SHARED || id == ZmId.SEARCH_ALL_ACCOUNTS) 428 ? DwtMenuItem.CHECK_STYLE : DwtMenuItem.RADIO_STYLE; 429 params.imageInfo = ZmSearchToolBar.ICON[id]; 430 params.text = ZmMsg[ZmSearchToolBar.MSG_KEY[id]]; 431 params.id = ZmSearchToolBar.ID[id]; 432 mi = DwtMenuItem.create(params); 433 mi.setData(ZmOperation.MENUITEM_ID, id); 434 if (!isCheckStyle) { 435 mi.setAttribute('aria-label', ZmMsg[ZmSearchToolBar.TT_MSG_KEY[id]]); 436 } 437 } 438 439 this._checkSharedMenuItem(); 440 appCtxt.getSettings().getSetting(ZmSetting.SEARCH_INCLUDES_SHARED).addChangeListener(this._checkSharedMenuItem.bind(this)); 441 442 appCtxt.getSearchController()._addMenuListeners(menu); 443 this._searchMenuCreated = true; 444 445 return menu; 446 }; 447 448 ZmMainSearchToolBar.prototype.setOfflineState = function(offline) { 449 var button = this._button[ZmSearchToolBar.TYPES_BUTTON]; 450 var menu = button && button.getMenu(); 451 var numItems = menu.getItemCount(); 452 for (var i = 0; i < numItems; i++) { 453 var item = menu.getItem(i); 454 if (item) { 455 var id = item.getData(ZmOperation.MENUITEM_ID); 456 if (id && ZmSearchToolBar.DISABLE_OFFLINE[id]) { 457 item.setEnabled(!offline); 458 } 459 } 460 } 461 } 462 463 ZmMainSearchToolBar.prototype.getSearchType = 464 function() { 465 var button = this._button[ZmSearchToolBar.TYPES_BUTTON]; 466 var menu = button && button.getMenu(); 467 var item = menu ? menu.getSelectedItem() || menu.getItems()[0] : null; 468 var data = item ? item.getData(ZmMainSearchToolBar.CUSTOM_ITEM_ID) || item.getData(ZmOperation.MENUITEM_ID) : 469 ZmSearchToolBar.MENU_ITEMS[0]; 470 return data; 471 }; 472 473 ZmMainSearchToolBar.prototype.createCustomSearchBtn = 474 function(icon, text, listener, id) { 475 476 if (!this._customSearchListener) { 477 this._customSearchListener = this._customSearchBtnListener.bind(this); 478 } 479 480 // check if custom search should be a button by checking for the Id against the template 481 var customSearchBtn = document.getElementById(this._htmlElId + "_customSearchButton"); 482 if (customSearchBtn) { 483 var data = { icon:icon, text:text, listener:listener }; 484 var button = this._button[ZmSearchToolBar.CUSTOM_BUTTON] 485 if (!button) { 486 button = this._button[ZmSearchToolBar.CUSTOM_BUTTON] = ZmToolBar.addButton({ 487 parent: this, 488 tdId: "_customSearchButton", 489 buttonId: ZmId.getButtonId(ZmId.SEARCH, ZmId.SEARCH_CUSTOM), 490 lbl: text, 491 icon: icon 492 }); 493 button.setData(ZmMainSearchToolBar.CUSTOM_ITEM_ID, data); 494 button.addSelectionListener(this._customSearchListener); 495 496 // show the separator now that we've added a custom search button 497 var sep = document.getElementById(this._htmlElId + "_customSearchButtonSep"); 498 if (sep) { 499 Dwt.setVisible(sep, true); 500 } 501 } else { 502 var menu = button && button.getMenu(); 503 var item; 504 var params = { 505 parent: menu, 506 enabled: true, 507 style: DwtMenuItem.RADIO_STYLE, 508 radioGroupId: 0, 509 id: id 510 }; 511 if (!menu) { 512 var btnData = button.getData(ZmMainSearchToolBar.CUSTOM_ITEM_ID); 513 menu = new DwtMenu({ 514 parent: button, 515 className: "ActionMenu", 516 id: ZmId.getMenuId(ZmId.SEARCH, ZmId.SEARCH_CUSTOM) 517 }); 518 button.setMenu(menu, false, DwtMenuItem.RADIO_STYLE); 519 params.imageInfo = btnData.icon; 520 params.text = btnData.text; 521 item = DwtMenuItem.create(params); 522 item.setData(ZmMainSearchToolBar.CUSTOM_ITEM_ID, btnData); 523 item.setData(ZmOperation.MENUITEM_ID, ZmId.SEARCH_CUSTOM); 524 item.setChecked(true, true); 525 item.addSelectionListener(this._customSearchListener); 526 } 527 params.imageInfo = icon; 528 params.text = text; 529 item = DwtMenuItem.create(params); 530 item.setData(ZmMainSearchToolBar.CUSTOM_ITEM_ID, data); 531 item.addSelectionListener(this._customSearchListener); 532 } 533 } else { 534 if (this._searchMenuCreated) { 535 var menu = this._button[ZmSearchToolBar.TYPES_BUTTON].getMenu(); 536 this._createCustomSearchMenuItem(menu, icon, text, listener, id); 537 } else { 538 if (!this._customSearchMenuItems) { 539 this._customSearchMenuItems = []; 540 } 541 this._customSearchMenuItems.push({icon:icon, text:text, listener:listener, id:id}); 542 } 543 } 544 }; 545 546 ZmMainSearchToolBar.prototype._createCustomSearchMenuItem = 547 function(menu, icon, text, listener, id) { 548 var mi = menu.getItem(0); 549 var params = { 550 parent: menu, 551 imageInfo: icon, 552 text: text, 553 enabled: true, 554 style: DwtMenuItem.RADIO_STYLE, 555 radioGroupId: 0, 556 index: 0, 557 id: id 558 }; 559 mi = DwtMenuItem.create(params); 560 var data = { icon:icon, text:text, listener:listener }; 561 mi.setData(ZmMainSearchToolBar.CUSTOM_ITEM_ID, data); 562 mi.setData(ZmOperation.MENUITEM_ID, ZmId.SEARCH_CUSTOM); 563 mi.addSelectionListener(this._customSearchListener); 564 565 // only add separator if this is the first custom search menu item 566 if (!(mi && mi.getData(ZmMainSearchToolBar.CUSTOM_ITEM_ID))) { 567 mi = new DwtMenuItem({parent:menu, style:DwtMenuItem.SEPARATOR_STYLE, index:1}); 568 } 569 }; 570 571 ZmMainSearchToolBar.prototype._customSearchBtnListener = 572 function(ev) { 573 var item = ev.item; 574 if (!item) { return; } 575 var data = item.getData(ZmMainSearchToolBar.CUSTOM_ITEM_ID); 576 if (!data) { return; } 577 if (this._customSearchBtn) { 578 if (item.isDwtMenuItem) { 579 if (ev.detail != DwtMenuItem.CHECKED) { return; } 580 this._customSearchBtn.setToolTipContent(data[1]); 581 this._customSearchBtn.setData(ZmMainSearchToolBar.CUSTOM_ITEM_ID, data); 582 } 583 data.listener.run(ev); // call original listener 584 } else { 585 var button = this._button[ZmSearchToolBar.TYPES_BUTTON]; 586 button.setToolTipContent(data.text); 587 588 var menu = item.parent; 589 var shareMenuItem = menu ? menu.getItemById(ZmOperation.MENUITEM_ID, ZmId.SEARCH_SHARED) : null; 590 if (shareMenuItem) { 591 shareMenuItem.setChecked(false, true); 592 shareMenuItem.setEnabled(false); 593 } 594 595 button.setImage(data.icon); 596 button.setText(data.text); 597 } 598 }; 599 600 // Expand INPUT when it gets focus 601 ZmMainSearchToolBar.prototype._onInputFocus = function(ev) { 602 603 this._setInputExpanded(true); 604 }; 605 606 // Collapse INPUT when it loses focus (unless that was due to a click on a search toolbar button) 607 ZmMainSearchToolBar.prototype._onInputBlur = function(ev) { 608 609 var focusObj = appCtxt.getKeyboardMgr().getFocusObj(); 610 if (focusObj !== this._button[ZmSearchToolBar.TYPES_BUTTON] && focusObj !== this._button[ZmSearchToolBar.SEARCH_BUTTON] && !this._movingFocus) { 611 this._setInputExpanded(false); 612 } 613 this._movingFocus = false; // done here since blur handler may be called on a timer 614 }; 615 616 // note when we're moving focus within the toolbar so we don't collapse the INPUT 617 ZmMainSearchToolBar.prototype._moveFocus = function(back) { 618 619 this._movingFocus = true; 620 ZmSearchToolBar.prototype._moveFocus.apply(this, arguments); 621 }; 622 623 ZmMainSearchToolBar.prototype._setInputExpanded = function(expanded) { 624 625 // Don't collapse input if user just popped up menu (which causes blur on input) 626 if (!expanded && this._searchMenu && this._searchMenu.isPoppedUp()) { 627 return; 628 } 629 630 var input = this._searchField.getInputElement(); 631 var cls = expanded ? "search_input-expanded" : "search_input"; 632 633 if (AjxEnv.isIE9) { 634 // bug 83493: IE9 gets the layout wrong on the first try 635 setTimeout(function() { 636 input.className = cls; 637 }, 0); 638 } else { 639 input.className = cls; 640 } 641 }; 642 643 ZmMainSearchToolBar.prototype._checkSharedMenuItem = 644 function() { 645 var mi = this._searchMenu && this._searchMenu.getItemById(ZmOperation.MENUITEM_ID, ZmId.SEARCH_SHARED); 646 if (mi) { 647 mi.setChecked(appCtxt.get(ZmSetting.SEARCH_INCLUDES_SHARED)); 648 } 649 }; 650