3 # ***** BEGIN LICENSE BLOCK *****
4 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 # The contents of this file are subject to the Mozilla Public License Version
7 # 1.1 (the "License"); you may not use this file except in compliance with
8 # the License. You may obtain a copy of the License at
9 # http://www.mozilla.org/MPL/
11 # Software distributed under the License is distributed on an "AS IS" basis,
12 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 # for the specific language governing rights and limitations under the
16 # The Original Code is mozilla.org browser.
18 # The Initial Developer of the Original Code is
20 # Portions created by the Initial Developer are Copyright (C) 2003
21 # the Initial Developer. All Rights Reserved.
24 # Pierre Chanial (v2) <p_ch@verizon.net>
25 # Gavin Sharp (v3) <gavin@gavinsharp.com>
26 # Ben Goodger <beng@google.com>
27 # Pamela Greene <pamg.bugs@gmail.com>
28 # Michael Ventnor <m.ventnor@gmail.com>
29 # Ehsan Akhgari <ehsan.akhgari@gmail.com>
31 # Alternatively, the contents of this file may be used under the terms of
32 # either the GNU General Public License Version 2 or later (the "GPL"), or
33 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 # in which case the provisions of the GPL or the LGPL are applicable instead
35 # of those above. If you wish to allow use of your version of this file only
36 # under the terms of either the GPL or the LGPL, and not to allow others to
37 # use your version of this file under the terms of the MPL, indicate your
38 # decision by deleting the provisions above and replace them with the notice
39 # and other provisions required by the GPL or the LGPL. If you do not delete
40 # the provisions above, a recipient may use your version of this file under
41 # the terms of any one of the MPL, the GPL or the LGPL.
43 # ***** END LICENSE BLOCK *****
46 <!ENTITY % searchBarDTD SYSTEM "chrome://browser/locale/searchbar.dtd" >
48 <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
50 <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
54 <bindings id="SearchBindings"
55 xmlns="http://www.mozilla.org/xbl"
56 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
57 xmlns:xbl="http://www.mozilla.org/xbl">
59 <binding id="searchbar">
61 <stylesheet src="chrome://browser/content/search/searchbarBindings.css"/>
62 <stylesheet src="chrome://browser/skin/searchbar.css"/>
65 <xul:stringbundle src="chrome://browser/locale/search.properties"
66 anonid="searchbar-stringbundle"/>
68 <xul:textbox class="searchbar-textbox"
69 anonid="searchbar-textbox"
72 autocompletepopup="PopupAutoComplete"
73 autocompletesearch="search-autocomplete"
74 autocompletesearchparam="searchbar-history"
77 completeselectedindex="true"
78 showcommentcolumn="true"
80 xbl:inherits="disabled,disableautocomplete,searchengine,src,newlines">
81 <xul:button class="searchbar-engine-button"
83 anonid="searchbar-engine-button"
85 chromedir="&locale.dir;">
86 <xul:image class="searchbar-engine-image" xbl:inherits="src"/>
87 <xul:image class="searchbar-dropmarker-image"/>
88 <xul:menupopup class="searchbar-popup"
89 anonid="searchbar-popup"
90 position="after_start">
92 <xul:menuitem class="open-engine-manager"
93 anonid="open-engine-manager"
94 label="&cmd_engineManager.label;"
95 # The empty tooltiptext attribute is here to avoid bug 336231
97 oncommand="openManager(event);"/>
100 <xul:hbox class="search-go-container" chromedir="&locale.dir;">
101 <xul:image class="search-go-button"
102 anonid="search-go-button"
103 chromedir="&locale.dir;"
104 onclick="handleSearchCommand(event);"
105 tooltiptext="&searchEndCap.label;" />
110 <implementation implements="nsIObserver">
112 <constructor><![CDATA[
113 if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
115 setTimeout(function (a) { a.init(); }, 0, this);
120 // Make sure we rebuild the popup in onpopupshowing
121 this._needToBuildPopup = true;
123 // Refresh the display (updating icon, etc)
124 this.updateDisplay();
127 Components.classes["@mozilla.org/observer-service;1"]
128 .getService(Components.interfaces.nsIObserverService);
129 os.addObserver(this, "browser-search-engine-modified", false);
131 this._addedObserver = true;
135 <destructor><![CDATA[
136 if (this._addedObserver) {
137 var os = Components.classes["@mozilla.org/observer-service;1"]
138 .getService(Components.interfaces.nsIObserverService);
139 os.removeObserver(this, "browser-search-engine-modified");
142 // Make sure to break the cycle from _texbox to us. Otherwise we leak
143 // the world. But make sure it's actually pointing to us.
144 if (this._textbox.mController.input == this)
145 this._textbox.mController.input = null;
148 <field name="_stringBundle">document.getAnonymousElementByAttribute(this,
149 "anonid", "searchbar-stringbundle");</field>
150 <field name="_textbox">document.getAnonymousElementByAttribute(this,
151 "anonid", "searchbar-textbox");</field>
152 <field name="_popup">document.getAnonymousElementByAttribute(this,
153 "anonid", "searchbar-popup");</field>
154 <field name="_ss">null</field>
155 <field name="_engines">null</field>
157 <property name="engines" readonly="true">
160 this._engines = this.searchService.getVisibleEngines({ });
161 return this._engines;
165 <field name="searchButton">document.getAnonymousElementByAttribute(this,
166 "anonid", "searchbar-engine-button");</field>
168 <property name="currentEngine"
169 onset="this.searchService.currentEngine = val; return val;">
171 var currentEngine = this.searchService.currentEngine;
172 // Return a dummy engine if there is no currentEngine
173 return currentEngine || {name:"", uri:null};
177 <!-- textbox is used by sanitize.js to clear the undo history when
178 clearing form information. -->
179 <property name="textbox" readonly="true"
180 onget="return this._textbox;"/>
182 <property name="searchService" readonly="true">
185 const nsIBSS = Components.interfaces.nsIBrowserSearchService;
187 Components.classes["@mozilla.org/browser/search-service;1"]
194 <property name="value" onget="return this._textbox.value;"
195 onset="return this._textbox.value = val;"/>
197 <method name="focus">
199 this._textbox.focus();
203 <method name="select">
205 this._textbox.select();
209 <method name="observe">
210 <parameter name="aEngine"/>
211 <parameter name="aTopic"/>
212 <parameter name="aVerb"/>
214 if (aTopic == "browser-search-engine-modified") {
216 case "engine-removed":
217 this.offerNewEngine(aEngine);
220 this.hideNewEngine(aEngine);
222 case "engine-current":
223 // The current engine was changed. Rebuilding the menu appears to
224 // confuse its idea of whether it should be open when it's just
225 // been clicked, so we force it to close now.
226 this._popup.hidePopup();
228 case "engine-changed":
229 // An engine was removed (or hidden) or added, or an icon was
230 // changed. Do nothing special.
233 // Make sure the engine list is refetched next time it's needed
234 this._engines = null;
236 // Rebuild the popup and update the display after any modification.
238 this.updateDisplay();
243 <!-- There are two seaprate lists of search engines, whose uses intersect
244 in this file. The search service (nsIBrowserSearchService and
245 nsSearchService.js) maintains a list of Engine objects which is used to
246 populate the searchbox list of available engines and to perform queries.
247 That list is accessed here via this.SearchService, and it's that sort of
248 Engine that is passed to this binding's observer as aEngine.
250 In addition, browser.js fills two lists of autodetected search engines
251 (browser.engines and browser.hiddenEngines) as properties of
252 mCurrentBrowser. Those lists contain unnamed JS objects of the form
253 { uri:, title:, icon: }, and that's what the searchbar uses to determine
254 whether to show any "Add <EngineName>" menu items in the drop-down.
256 The two types of engines are currently related by their identifying
257 titles (the Engine object's 'name'), although that may change; see bug
260 <!-- If the engine that was just removed from the searchbox list was
261 autodetected on this page, move it to each browser's active list so it
262 will be offered to be added again. -->
263 <method name="offerNewEngine">
264 <parameter name="aEngine"/>
266 var allbrowsers = getBrowser().mPanelContainer.childNodes;
267 for (var tab = 0; tab < allbrowsers.length; tab++) {
268 var browser = getBrowser().getBrowserAtIndex(tab);
269 if (browser.hiddenEngines) {
270 // XXX This will need to be changed when engines are identified by
271 // URL rather than title; see bug 335102.
272 var removeTitle = aEngine.wrappedJSObject.name;
273 for (var i = 0; i < browser.hiddenEngines.length; i++) {
274 if (browser.hiddenEngines[i].title == removeTitle) {
275 if (!browser.engines)
276 browser.engines = [];
277 browser.engines.push(browser.hiddenEngines[i]);
278 browser.hiddenEngines.splice(i, 1);
284 BrowserSearch.updateSearchButton();
288 <!-- If the engine that was just added to the searchbox list was
289 autodetected on this page, move it to each browser's hidden list so it is
290 no longer offered to be added. -->
291 <method name="hideNewEngine">
292 <parameter name="aEngine"/>
294 var allbrowsers = getBrowser().mPanelContainer.childNodes;
295 for (var tab = 0; tab < allbrowsers.length; tab++) {
296 var browser = getBrowser().getBrowserAtIndex(tab);
297 if (browser.engines) {
298 // XXX This will need to be changed when engines are identified by
299 // URL rather than title; see bug 335102.
300 var removeTitle = aEngine.wrappedJSObject.name;
301 for (var i = 0; i < browser.engines.length; i++) {
302 if (browser.engines[i].title == removeTitle) {
303 if (!browser.hiddenEngines)
304 browser.hiddenEngines = [];
305 browser.hiddenEngines.push(browser.engines[i]);
306 browser.engines.splice(i, 1);
312 BrowserSearch.updateSearchButton();
316 <method name="updateDisplay">
318 var uri = this.currentEngine.iconURI;
319 this.setAttribute("src", uri ? uri.spec : "");
321 var name = this.currentEngine.name;
322 var text = this._stringBundle.getFormattedString("searchtip", [name]);
323 this._textbox.emptyText = name;
324 this._textbox.label = text;
325 this._textbox.tooltipText = text;
329 <!-- Rebuilds the dynamic portion of the popup menu (i.e., the menu items
330 for new search engines that can be added to the available list). This
331 is called each time the popup is shown.
333 <method name="rebuildPopupDynamic">
335 // We might not have added the main popup items yet, do that first
337 if (this._needToBuildPopup)
340 var popup = this._popup;
341 // Clear any addengine menuitems, including addengine-item entries and
342 // the addengine-separator. Work backward to avoid invalidating the
343 // indexes as items are removed.
344 var items = popup.childNodes;
345 for (var i = items.length - 1; i >= 0; i--) {
346 if (items[i].getAttribute("class").indexOf("addengine") != -1)
347 popup.removeChild(items[i]);
350 var addengines = getBrowser().mCurrentBrowser.engines;
351 if (addengines && addengines.length > 0) {
353 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
355 // Find the (first) separator in the remaining menu, or the first item
356 // if no separators are present.
357 var insertLocation = popup.firstChild;
358 while (insertLocation.nextSibling &&
359 insertLocation.localName != "menuseparator") {
360 insertLocation = insertLocation.nextSibling;
362 if (insertLocation.localName != "menuseparator")
363 insertLocation = popup.firstChild;
365 var separator = document.createElementNS(kXULNS, "menuseparator");
366 separator.setAttribute("class", "addengine-separator");
367 popup.insertBefore(separator, insertLocation);
369 // Insert the "add this engine" items.
370 for (var i = 0; i < addengines.length; i++) {
371 var menuitem = document.createElement("menuitem");
372 var engineInfo = addengines[i];
374 this._stringBundle.getFormattedString("cmd_addFoundEngine",
376 menuitem = document.createElementNS(kXULNS, "menuitem");
377 menuitem.setAttribute("class", "menuitem-iconic addengine-item");
378 menuitem.setAttribute("label", labelStr);
379 menuitem.setAttribute("tooltiptext", engineInfo.uri);
380 menuitem.setAttribute("uri", engineInfo.uri);
382 menuitem.setAttribute("src", engineInfo.icon);
383 menuitem.setAttribute("title", engineInfo.title);
384 popup.insertBefore(menuitem, insertLocation);
390 <!-- Rebuilds the list of visible search engines in the menu. Does not remove
391 or update any dynamic entries (i.e., "Add this engine" items) nor the
392 Manage Engines item. This is called by the observer when the list of
393 visible engines, or the currently selected engine, has changed.
395 <method name="rebuildPopup">
397 var popup = this._popup;
399 // Clear the popup, down to the first separator
400 while (popup.firstChild && popup.firstChild.localName != "menuseparator")
401 popup.removeChild(popup.firstChild);
404 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
406 var engines = this.engines;
407 for (var i = engines.length - 1; i >= 0; --i) {
408 var menuitem = document.createElementNS(kXULNS, "menuitem");
409 var name = engines[i].name;
410 menuitem.setAttribute("label", name);
411 menuitem.setAttribute("id", name);
412 menuitem.setAttribute("class", "menuitem-iconic searchbar-engine-menuitem");
413 // Since this menu is rebuilt by the observer method whenever a new
414 // engine is selected, the "selected" attribute does not need to be
415 // explicitly cleared anywhere.
416 if (engines[i] == this.currentEngine)
417 menuitem.setAttribute("selected", "true");
418 var tooltip = this._stringBundle.getFormattedString("searchtip", [name]);
419 menuitem.setAttribute("tooltiptext", tooltip);
420 if (engines[i].iconURI)
421 menuitem.setAttribute("src", engines[i].iconURI.spec);
422 popup.insertBefore(menuitem, popup.firstChild);
423 menuitem.engine = engines[i];
426 this._needToBuildPopup = false;
430 <method name="openManager">
431 <parameter name="aEvent"/>
434 Components.classes["@mozilla.org/appshell/window-mediator;1"]
435 .getService(Components.interfaces.nsIWindowMediator);
437 var window = wm.getMostRecentWindow("Browser:SearchManager");
441 setTimeout(function () {
442 openDialog("chrome://browser/content/search/engineManager.xul",
443 "_blank", "chrome,dialog,modal,centerscreen");
449 <method name="selectEngine">
450 <parameter name="aEvent"/>
451 <parameter name="isNextEngine"/>
453 // Find the new index
454 var newIndex = this.engines.indexOf(this.currentEngine);
455 newIndex += (isNextEngine) ? 1 : -1;
457 if (newIndex >= 0 && newIndex < this.engines.length)
458 this.currentEngine = this.engines[newIndex];
460 aEvent.preventDefault();
461 aEvent.stopPropagation();
465 <method name="handleSearchCommand">
466 <parameter name="aEvent"/>
468 var textBox = this._textbox;
469 var textValue = textBox.value;
471 var where = "current";
472 if (aEvent && aEvent.originalTarget.getAttribute("anonid") == "search-go-button") {
473 if (aEvent.button == 2)
475 where = whereToOpenLink(aEvent, false, true);
478 var newTabPref = textBox._prefBranch.getBoolPref("browser.search.openintab");
479 if ((aEvent && aEvent.altKey) ^ newTabPref)
483 // Save the current value in the form history
485 textBox._formHistSvc.addEntry(textBox.getAttribute("autocompletesearchparam"),
489 this.doSearch(textValue, where);
493 <method name="doSearch">
494 <parameter name="aData"/>
495 <parameter name="aWhere"/>
497 // null parameter below specifies HTML response for search
498 var submission = this.currentEngine.getSubmission(aData, null);
499 openUILinkIn(submission.uri.spec, aWhere, null, submission.postData);
506 <handler event="command"><![CDATA[
507 const target = event.originalTarget;
508 if (target.getAttribute("class").indexOf("addengine-item") != -1) {
510 Components.classes["@mozilla.org/browser/search-service;1"]
511 .getService(Components.interfaces.nsIBrowserSearchService);
512 // We only detect OpenSearch files
513 var type = Components.interfaces.nsISearchEngine.DATA_XML;
514 searchService.addEngine(target.getAttribute("uri"), type,
515 target.getAttribute("src"), false);
517 else if (target.engine)
518 this.currentEngine = target.engine;
526 <handler event="popupshowing" action="this.rebuildPopupDynamic();"/>
528 <handler event="DOMMouseScroll"
531 action="if (event.metaKey) this.selectEngine(event, (event.detail > 0));"/>
533 action="if (event.ctrlKey) this.selectEngine(event, (event.detail > 0));"/>
538 <binding id="searchbar-textbox"
539 extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
540 <implementation implements="nsIObserver">
541 <constructor><![CDATA[
542 if (document.getBindingParent(this).parentNode.parentNode.localName ==
543 "toolbarpaletteitem")
545 setTimeout(function(a) { a.initialize(); }, 0, this);
548 <destructor><![CDATA[
549 var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
550 .getService(Components.interfaces.nsIPrefBranch2);
551 ps2.removeObserver("browser.search.suggest.enabled", this);
553 // Because XBL and the customize toolbar code interacts poorly,
554 // there may not be anything to remove here
556 this.controllers.removeController(this.searchbarController);
560 <field name="_stringBundle"/>
561 <field name="_formHistSvc"/>
562 <field name="_prefBranch"/>
563 <field name="_suggestMenuItem"/>
564 <field name="_suggestEnabled"/>
566 <method name="initialize">
569 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
571 this._stringBundle = document.getBindingParent(this)._stringBundle;
573 Components.classes["@mozilla.org/satchel/form-history;1"]
574 .getService(Components.interfaces.nsIFormHistory2);
576 Components.classes["@mozilla.org/preferences-service;1"]
577 .getService(Components.interfaces.nsIPrefBranch);
578 this._suggestEnabled =
579 this._prefBranch.getBoolPref("browser.search.suggest.enabled");
581 if (this._prefBranch.getBoolPref("browser.urlbar.clickSelectsAll"))
582 this.setAttribute("clickSelectsAll", true);
584 // Add items to context menu and attach controller to handle them
585 var textBox = document.getAnonymousElementByAttribute(this,
586 "anonid", "textbox-input-box");
587 var cxmenu = document.getAnonymousElementByAttribute(textBox,
588 "anonid", "input-box-contextmenu");
590 var element = document.createElementNS(kXULNS, "menuseparator");
591 cxmenu.appendChild(element);
592 element = document.createElementNS(kXULNS, "menuitem");
593 var label = this._stringBundle.getString("cmd_clearHistory");
594 var akey = this._stringBundle.getString("cmd_clearHistory_accesskey");
595 element.setAttribute("label", label);
596 element.setAttribute("accesskey", akey);
597 element.setAttribute("cmd", "cmd_clearhistory");
599 cxmenu.appendChild(element);
601 element = document.createElementNS(kXULNS, "menuitem");
602 label = this._stringBundle.getString("cmd_showSuggestions");
603 akey = this._stringBundle.getString("cmd_showSuggestions_accesskey");
604 element.setAttribute("anonid", "toggle-suggest-item");
605 element.setAttribute("label", label);
606 element.setAttribute("accesskey", akey);
607 element.setAttribute("cmd", "cmd_togglesuggest");
608 element.setAttribute("type", "checkbox");
609 element.setAttribute("checked", this._suggestEnabled);
610 element.setAttribute("autocheck", "false");
612 this._suggestMenuItem = element;
613 cxmenu.appendChild(element);
615 this.controllers.appendController(this.searchbarController);
617 // Add observer for suggest preference
618 var ps2 = Components.classes["@mozilla.org/preferences-service;1"]
619 .getService(Components.interfaces.nsIPrefBranch2);
620 ps2.addObserver("browser.search.suggest.enabled", this, false);
624 <method name="openPopup">
626 var popup = this.popup;
627 if (!popup.mPopupOpen) {
628 // Initially the panel used for the searchbar (PopupAutoComplete
629 // in browser.xul) is hidden to avoid impacting startup / new
630 // window performance. The base binding's openPopup would normally
631 // call the overriden openAutocompletePopup in urlbarBindings.xml's
632 // browser-autocomplete-result-popup binding to unhide the popup,
633 // but since we're overriding openPopup we need to unhide the panel
635 popup.hidden = false;
638 popup.view = this.controller.QueryInterface(Components.interfaces.nsITreeView);
641 popup.showCommentColumn = this.showCommentColumn;
642 popup.showImageColumn = this.showImageColumn;
644 document.popupNode = null;
646 var outerRect = this.getBoundingClientRect();
647 var innerRect = this.inputField.getBoundingClientRect();
648 var width = outerRect.right - innerRect.left;
649 popup.setAttribute("width", width > 100 ? width : 100);
651 // setConsumeRollupEvent() before we call openPopup(),
652 // see bug #404438 for more details
653 popup.popupBoxObject.setConsumeRollupEvent(
654 this.consumeRollupEvent ?
655 Ci.nsIPopupBoxObject.ROLLUP_CONSUME :
656 Ci.nsIPopupBoxObject.ROLLUP_NO_CONSUME);
657 popup.openPopup(null, "", innerRect.left, outerRect.bottom, false, false);
662 <method name="observe">
663 <parameter name="aSubject"/>
664 <parameter name="aTopic"/>
665 <parameter name="aData"/>
667 if (aTopic == "nsPref:changed") {
668 this._suggestEnabled =
669 this._prefBranch.getBoolPref("browser.search.suggest.enabled");
670 this._suggestMenuItem.setAttribute("checked", this._suggestEnabled);
675 <method name="openSearch">
678 // Don't open search popup if history popup is open
679 if (!this.popupOpen) {
680 document.getBindingParent(this).searchButton.open = true;
688 <!-- overload |onTextEntered| in autocomplete.xml -->
689 <method name="onTextEntered">
690 <parameter name="aEvent"/>
692 var evt = aEvent || this.mEnterEvent;
693 document.getBindingParent(this).handleSearchCommand(evt);
694 this.mEnterEvent = null;
698 <!-- nsIController -->
699 <field name="searchbarController" readonly="true"><![CDATA[({
701 supportsCommand: function(aCommand) {
702 return aCommand == "cmd_clearhistory" ||
703 aCommand == "cmd_togglesuggest";
706 isCommandEnabled: function(aCommand) {
707 if (aCommand == "cmd_clearhistory") {
708 var param = this._self.getAttribute("autocompletesearchparam");
709 return this._self._formHistSvc.nameExists(param);
714 doCommand: function (aCommand) {
716 case "cmd_clearhistory":
717 var param = this._self.getAttribute("autocompletesearchparam");
718 this._self._formHistSvc.removeEntriesForName(param);
719 this._self.value = "";
721 case "cmd_togglesuggest":
722 // The pref observer will update _suggestEnabled and the menu
724 this._self._prefBranch.setBoolPref("browser.search.suggest.enabled",
725 !this._self._suggestEnabled);
728 // do nothing with unrecognized command
733 <!-- DND Observer -->
734 <field name="searchbarDNDObserver" readonly="true"><![CDATA[({
737 onDrop: function (aEvent, aXferData, aDragSession) {
738 var data = transferUtils.retrieveURLFromData(aXferData.data,
739 aXferData.flavour.contentType);
741 this.mOuter.value = data;
742 this.mOuter.onTextEntered(aEvent);
746 getSupportedFlavours: function () {
747 var flavourSet = new FlavourSet();
749 flavourSet.appendFlavour("text/unicode");
750 flavourSet.appendFlavour("text/x-moz-url");
751 flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
758 <handler event="keypress" keycode="VK_UP" modifiers="accel"
760 action="document.getBindingParent(this).selectEngine(event, false);"/>
762 <handler event="keypress" keycode="VK_DOWN" modifiers="accel"
764 action="document.getBindingParent(this).selectEngine(event, true);"/>
766 <handler event="keypress" keycode="VK_DOWN" modifiers="alt"
768 action="return this.openSearch();"/>
770 <handler event="keypress" keycode="VK_UP" modifiers="alt"
772 action="return this.openSearch();"/>
775 <handler event="keypress" keycode="VK_F4"
777 action="return this.openSearch();"/>
780 <handler event="drop" phase="capturing">
781 nsDragAndDrop.drop(event, this.searchbarDNDObserver);