diff options
Diffstat (limited to 'mailnews/base/search/content/searchWidgets.xml')
-rw-r--r-- | mailnews/base/search/content/searchWidgets.xml | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/mailnews/base/search/content/searchWidgets.xml b/mailnews/base/search/content/searchWidgets.xml new file mode 100644 index 000000000..80ebe38c4 --- /dev/null +++ b/mailnews/base/search/content/searchWidgets.xml @@ -0,0 +1,738 @@ +<?xml version="1.0"?> + +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<!-- + This file has the following external dependencies: + -gFilterActionStrings from FilterEditor.js + -gFilterList from FilterEditor.js + -gFilter from FilterEditor.js + -gCustomActions from FilterEditor.js + -gFilterType from FilterEditor.js + -checkActionsReorder from FilterEditor.js +--> + +<!DOCTYPE dialog [ + <!ENTITY % filterEditorDTD SYSTEM "chrome://messenger/locale/FilterEditor.dtd" > +%filterEditorDTD; + <!ENTITY % messengerDTD SYSTEM "chrome://messenger/locale/messenger.dtd" > +%messengerDTD; +]> + +<bindings id="filterBindings" + xmlns="http://www.mozilla.org/xbl" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:nc="http://home.netscape.com/NC-rdf#" + xmlns:xbl="http://www.mozilla.org/xbl"> + + <binding id="ruleactiontype-menulist"> + <content> + <xul:menulist class="ruleaction-type"> + <xul:menupopup> + <xul:menuitem label="&moveMessage.label;" value="movemessage" enablefornews="false"/> + <xul:menuitem label="©Message.label;" value="copymessage"/> + <xul:menuseparator enablefornews="false"/> + <xul:menuitem label="&forwardTo.label;" value="forwardmessage" enablefornews="false"/> + <xul:menuitem label="&replyWithTemplate.label;" value="replytomessage" enablefornews="false"/> + <xul:menuseparator/> + <xul:menuitem label="&markMessageRead.label;" value="markasread"/> + <xul:menuitem label="&markMessageUnread.label;" value="markasunread"/> + <xul:menuitem label="&markMessageStarred.label;" value="markasflagged"/> + <xul:menuitem label="&setPriority.label;" value="setpriorityto"/> + <xul:menuitem label="&addTag.label;" value="addtagtomessage"/> + <xul:menuitem label="&setJunkScore.label;" value="setjunkscore" enablefornews="false"/> + <xul:menuseparator enableforpop3="true"/> + <xul:menuitem label="&deleteMessage.label;" value="deletemessage"/> + <xul:menuitem label="&deleteFromPOP.label;" value="deletefrompopserver" enableforpop3="true"/> + <xul:menuitem label="&fetchFromPOP.label;" value="fetchfrompopserver" enableforpop3="true"/> + <xul:menuseparator/> + <xul:menuitem label="&ignoreThread.label;" value="ignorethread"/> + <xul:menuitem label="&ignoreSubthread.label;" value="ignoresubthread"/> + <xul:menuitem label="&watchThread.label;" value="watchthread"/> + <xul:menuseparator/> + <xul:menuitem label="&stopExecution.label;" value="stopexecution"/> + </xul:menupopup> + </xul:menulist> + </content> + + <implementation> + <constructor> + <![CDATA[ + this.addCustomActions(); + this.hideInvalidActions(); + // differentiate between creating a new, next available action, + // and creating a row which will be initialized with an action + if (!this.parentNode.hasAttribute('initialActionIndex')) + { + var unavailableActions = this.usedActionsList(); + // select the first one that's not in the list + for (var index = 0; index < this.menuitems.length; index++) + { + var menu = this.menuitems[index]; + if (!(menu.value in unavailableActions) && !menu.hidden) + { + this.menulist.value = menu.value; + this.parentNode.setAttribute('value', menu.value); + break; + } + } + } + else + { + this.parentNode.mActionTypeInitialized = true; + this.parentNode.clearInitialActionIndex(); + } + ]]> + </constructor> + + <field name="menulist">document.getAnonymousNodes(this)[0]</field> + <field name="menuitems">this.menulist.getElementsByTagNameNS(this.menulist.namespaceURI, 'menuitem')</field> + + <method name="hideInvalidActions"> + <body> + <![CDATA[ + let menupopup = this.menulist.menupopup; + let scope = getScopeFromFilterList(gFilterList); + + // walk through the list of filter actions and hide any actions which aren't valid + // for our given scope (news, imap, pop, etc) and context + let elements, i; + + // disable / enable all elements in the "filteractionlist" + // based on the scope and the "enablefornews" attribute + elements = menupopup.getElementsByAttribute("enablefornews", "true"); + for (i = 0; i < elements.length; i++) + elements[i].hidden = scope != Components.interfaces.nsMsgSearchScope.newsFilter; + + elements = menupopup.getElementsByAttribute("enablefornews", "false"); + for (i = 0; i < elements.length; i++) + elements[i].hidden = scope == Components.interfaces.nsMsgSearchScope.newsFilter; + + elements = menupopup.getElementsByAttribute("enableforpop3", "true"); + for (i = 0; i < elements.length; i++) + elements[i].hidden = !((gFilterList.folder.server.type == "pop3") || + (gFilterList.folder.server.type == "none")); + + elements = menupopup.getElementsByAttribute("isCustom", "true"); + // Note there might be an additional element here as a placeholder + // for a missing action, so we iterate over the known actions + // instead of the elements. + for (i = 0; i < gCustomActions.length; i++) + elements[i].hidden = !gCustomActions[i] + .isValidForType(gFilterType, scope); + + // Disable "Reply with Template" if there are no templates. + if (!this.getTemplates(false)) { + elements = menupopup.getElementsByAttribute("value", "replytomessage"); + if (elements.length == 1) + elements[0].hidden = true; + } + ]]> + </body> + </method> + + <method name="addCustomActions"> + <body> + <![CDATA[ + var menupopup = this.menulist.menupopup; + for (var i = 0; i < gCustomActions.length; i++) + { + var customAction = gCustomActions[i]; + var menuitem = document.createElementNS( + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", + "xul:menuitem"); + menuitem.setAttribute("label", customAction.name); + menuitem.setAttribute("value", customAction.id); + menuitem.setAttribute("isCustom", "true"); + menupopup.appendChild(menuitem); + } + ]]> + </body> + </method> + + <!-- returns a hash containing all of the filter actions which are currently being used by other filteractionrows --> + <method name="usedActionsList"> + <body> + <![CDATA[ + var usedActions = {}; + var currentFilterActionRow = this.parentNode; + var listBox = currentFilterActionRow.mListBox; // need to account for the list item + // now iterate over each list item in the list box + for (var index = 0; index < listBox.getRowCount(); index++) + { + var filterActionRow = listBox.getItemAtIndex(index); + if (filterActionRow != currentFilterActionRow) + { + var actionValue = filterActionRow.getAttribute('value'); + + // let custom actions decide if dups are allowed + var isCustom = false; + for (var i = 0; i < gCustomActions.length; i++) + { + if (gCustomActions[i].id == actionValue) + { + isCustom = true; + if (!gCustomActions[i].allowDuplicates) + usedActions[actionValue] = true; + break; + } + } + + if (!isCustom) { + // The following actions can appear more than once in a single filter + // so do not set them as already used. + if (actionValue != 'addtagtomessage' && + actionValue != 'forwardmessage' && + actionValue != 'copymessage') + usedActions[actionValue] = true; + // If either Delete message or Move message exists, disable the other one. + // It does not make sense to apply both to the same message. + if (actionValue == 'deletemessage') + usedActions['movemessage'] = true; + else if (actionValue == 'movemessage') + usedActions['deletemessage'] = true; + // The same with Mark as read/Mark as Unread. + else if (actionValue == 'markasread') + usedActions['markasunread'] = true; + else if (actionValue == 'markasunread') + usedActions['markasread'] = true; + } + } + } + return usedActions; + ]]> + </body> + </method> + + <!-- + - Check if there exist any templates in this account. + - + - @param populateTemplateList If true, create menuitems representing + - the found templates. + - @param templateMenuList The menulist element to create items in. + - + - @return True if at least one template was found, otherwise false. + --> + <method name="getTemplates"> + <parameter name="populateTemplateList"/> + <parameter name="templateMenuList"/> + <body> + <![CDATA[ + Components.utils.import("resource:///modules/iteratorUtils.jsm", this); + let identitiesRaw = MailServices.accounts + .getIdentitiesForServer(gFilterList.folder.server); + let identities = Array.from(this.fixIterator(identitiesRaw, + Components.interfaces.nsIMsgIdentity)); + + if (!identities.length) // typically if this is Local Folders + identities.push(MailServices.accounts.defaultAccount.defaultIdentity); + + let templateFound = false; + let foldersScanned = []; + + for (let identity of identities) { + let enumerator = null; + let msgFolder; + try { + msgFolder = Components.classes["@mozilla.org/rdf/rdf-service;1"] + .getService(Components.interfaces.nsIRDFService) + .GetResource(identity.stationeryFolder) + .QueryInterface(Components.interfaces.nsIMsgFolder); + // If we already processed this folder, do not set enumerator + // so that we skip this identity. + if (foldersScanned.indexOf(msgFolder) == -1) { + foldersScanned.push(msgFolder); + enumerator = msgFolder.msgDatabase.EnumerateMessages(); + } + } catch (e) { + // The Templates folder may not exist, that is OK. + } + + if (!enumerator) + continue; + + while (enumerator.hasMoreElements()) { + let header = enumerator.getNext(); + if (header instanceof Components.interfaces.nsIMsgDBHdr) { + templateFound = true; + if (!populateTemplateList) + return true; + let msgTemplateUri = msgFolder.URI + "?messageId=" + + header.messageId + '&subject=' + header.mime2DecodedSubject; + let newItem = templateMenuList.appendItem(header.mime2DecodedSubject, + msgTemplateUri); + } + } + } + + return templateFound; + ]]> + </body> + </method> + + </implementation> + + <handlers> + <handler event="command"> + <![CDATA[ + this.parentNode.setAttribute('value', this.menulist.value); + checkActionsReorder(); + ]]> + </handler> + + <handler event="popupshowing"> + <![CDATA[ + var unavailableActions = this.usedActionsList(); + for (var index = 0; index < this.menuitems.length; index++) + { + var menu = this.menuitems[index]; + menu.setAttribute('disabled', menu.value in unavailableActions); + } + ]]> + </handler> + </handlers> + </binding> + + <!-- This binding exists to disable the default binding of a listitem + in the search terms. --> + <binding id="listitem"> + <implementation> + <method name="_fireEvent"> + <parameter name="aName"/> + <body> + <![CDATA[ + /* This provides a dummy _fireEvent function that + the listbox expects to be able to call. + See bug 202036. */ + ]]> + </body> + </method> + </implementation> + </binding> + + <binding id="ruleaction" extends="#listitem"> + <content allowevents="true"> + <xul:listcell class="ruleactiontype" + orient="vertical" align="stretch" pack="center"/> + <xul:listcell class="ruleactiontarget" xbl:inherits="type=value" + orient="vertical" align="stretch" pack="center"/> + <xul:listcell> + <xul:button class="small-button" + label="+" + tooltiptext="&addAction.tooltip;" + oncommand="this.parentNode.parentNode.addRow();"/> + <xul:button class="small-button" + label="−" + tooltiptext="&removeAction.tooltip;" + oncommand="this.parentNode.parentNode.removeRow();" + anonid="removeButton"/> + </xul:listcell> + </content> + + <implementation> + <field name="mListBox">this.parentNode</field> + <field name="mRemoveButton">document.getAnonymousElementByAttribute(this, "anonid", "removeButton")</field> + <field name="mActionTypeInitialized">false</field> + <field name="mRuleActionTargetInitialized">false</field> + <field name="mRuleActionType">document.getAnonymousNodes(this)[0]</field> + + <method name="clearInitialActionIndex"> + <body> + <![CDATA[ + // we should only remove the initialActionIndex after we have been told that + // both the rule action type and the rule action target have both been built since they both need + // this piece of information. This complication arises because both of these child elements are getting + // bound asynchronously after the search row has been constructed + + if (this.mActionTypeInitialized && this.mRuleActionTargetInitialized) + this.removeAttribute('initialActionIndex'); + ]]> + </body> + </method> + + <method name="initWithAction"> + <parameter name="aFilterAction"/> + <body> + <![CDATA[ + var filterActionStr; + var actionTarget = document.getAnonymousNodes(this)[1]; + var actionItem = document.getAnonymousNodes(actionTarget); + var nsMsgFilterAction = Components.interfaces.nsMsgFilterAction; + switch (aFilterAction.type) + { + case nsMsgFilterAction.Custom: + filterActionStr = aFilterAction.customId; + if (actionItem) + actionItem[0].value = aFilterAction.strValue; + + // Make sure the custom action has been added. If not, it + // probably was from an extension that has been removed. We'll + // show a dummy menuitem to warn the user. + var needCustomLabel = true; + for (var i = 0; i < gCustomActions.length; i++) + { + if (gCustomActions[i].id == filterActionStr) + { + needCustomLabel = false; + break; + } + } + if (needCustomLabel) + { + var menuitem = document.createElementNS( + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", + "xul:menuitem"); + menuitem.setAttribute("label", + gFilterBundle.getString("filterMissingCustomAction")); + menuitem.setAttribute("value", filterActionStr); + menuitem.disabled = true; + this.mRuleActionType.menulist.menupopup.appendChild(menuitem); + var scriptError = Components.classes["@mozilla.org/scripterror;1"] + .createInstance(Components.interfaces.nsIScriptError); + scriptError.init("Missing custom action " + filterActionStr, + null, null, 0, 0, + Components.interfaces.nsIScriptError.errorFlag, + "component javascript"); + Services.console.logMessage(scriptError); + } + break; + case nsMsgFilterAction.MoveToFolder: + case nsMsgFilterAction.CopyToFolder: + actionItem[0].value = aFilterAction.targetFolderUri; + break; + case nsMsgFilterAction.Reply: + case nsMsgFilterAction.Forward: + actionItem[0].value = aFilterAction.strValue; + break; + case nsMsgFilterAction.Label: + actionItem[0].value = aFilterAction.label; + break; + case nsMsgFilterAction.ChangePriority: + actionItem[0].value = aFilterAction.priority; + break; + case nsMsgFilterAction.JunkScore: + actionItem[0].value = aFilterAction.junkScore; + break; + case nsMsgFilterAction.AddTag: + actionItem[0].value = aFilterAction.strValue; + break; + default: + break; + } + if (aFilterAction.type != nsMsgFilterAction.Custom) + filterActionStr = gFilterActionStrings[aFilterAction.type]; + document.getAnonymousNodes(this.mRuleActionType)[0] + .value = filterActionStr; + this.mRuleActionTargetInitialized = true; + this.clearInitialActionIndex(); + checkActionsReorder(); + ]]> + </body> + </method> + + <method name="validateAction"> + <body> + <![CDATA[ + // returns true if this row represents a valid filter action and false otherwise. + // This routine also prompts the user. + Components.utils.import("resource:///modules/MailUtils.js", this); + var filterActionString = this.getAttribute('value'); + var actionTarget = document.getAnonymousNodes(this)[1]; + var errorString, customError; + + switch (filterActionString) + { + case "movemessage": + case "copymessage": + let msgFolder = document.getAnonymousNodes(actionTarget)[0].value ? + this.MailUtils.getFolderForURI(document.getAnonymousNodes(actionTarget)[0].value) : null; + if (!msgFolder || !msgFolder.canFileMessages) + errorString = "mustSelectFolder"; + break; + case "forwardmessage": + if (document.getAnonymousNodes(actionTarget)[0].value.length < 3 || + document.getAnonymousNodes(actionTarget)[0].value.indexOf('@') < 1) + errorString = "enterValidEmailAddress"; + break; + case "replytomessage": + if (!document.getAnonymousNodes(actionTarget)[0].selectedItem) + errorString = "pickTemplateToReplyWith"; + break; + default: + // some custom actions have no action value node + if (!document.getAnonymousNodes(actionTarget)) + return true; + // locate the correct custom action, and check validity + for (var i = 0; i < gCustomActions.length; i++) + if (gCustomActions[i].id == filterActionString) + { + customError = + gCustomActions[i].validateActionValue( + document.getAnonymousNodes(actionTarget)[0].value, + gFilterList.folder, gFilterType); + break; + } + break; + } + + errorString = errorString ? + gFilterBundle.getString(errorString) : + customError; + if (errorString) + Services.prompt.alert(window, null, errorString); + + return !errorString; + ]]> + </body> + </method> + + <method name="saveToFilter"> + <parameter name="aFilter"/> + <body> + <![CDATA[ + // create a new filter action, fill it in, and then append it to the filter + var filterAction = aFilter.createAction(); + var filterActionString = this.getAttribute('value'); + filterAction.type = gFilterActionStrings.indexOf(filterActionString); + var actionTarget = document.getAnonymousNodes(this)[1]; + var actionItem = document.getAnonymousNodes(actionTarget); + var nsMsgFilterAction = Components.interfaces.nsMsgFilterAction; + switch (filterAction.type) + { + case nsMsgFilterAction.Label: + filterAction.label = actionItem[0].getAttribute("value"); + break; + case nsMsgFilterAction.ChangePriority: + filterAction.priority = actionItem[0].getAttribute("value"); + break; + case nsMsgFilterAction.MoveToFolder: + case nsMsgFilterAction.CopyToFolder: + filterAction.targetFolderUri = actionItem[0].value; + break; + case nsMsgFilterAction.JunkScore: + filterAction.junkScore = actionItem[0].value; + break; + case nsMsgFilterAction.Custom: + filterAction.customId = filterActionString; + // fall through to set the value + default: + if (actionItem) + filterAction.strValue = actionItem[0].value; + break; + } + aFilter.appendAction(filterAction); + ]]> + </body> + </method> + + <method name="getActionStrings"> + <parameter name="aActionStrings"/> + <body> + <![CDATA[ + // Collect the action names and arguments in a plain string form. + let actionTarget = document.getAnonymousNodes(this)[1]; + let actionItem = document.getAnonymousNodes(actionTarget); + + aActionStrings.push({ + label: document.getAnonymousNodes(this.mRuleActionType)[0].label, + argument: actionItem ? + (actionItem[0].label ? + actionItem[0].label : actionItem[0].value) : "" + }); + ]]> + </body> + </method> + + <method name="updateRemoveButton"> + <body> + <![CDATA[ + // if we only have one row of actions, then disable the remove button for that row + this.mListBox.getItemAtIndex(0).mRemoveButton.disabled = this.mListBox.getRowCount() == 1; + ]]> + </body> + </method> + + <method name="addRow"> + <body> + <![CDATA[ + let listItem = document.createElement('listitem'); + listItem.className = 'ruleaction'; + listItem.setAttribute('onfocus','this.storeFocus();'); + this.mListBox.insertBefore(listItem, this.nextSibling); + this.mListBox.ensureElementIsVisible(listItem); + + // make sure the first remove button is enabled + this.updateRemoveButton(); + checkActionsReorder(); + ]]> + </body> + </method> + + <method name="removeRow"> + <body> + <![CDATA[ + // this.mListBox will fail after the row is removed, so save it + let listBox = this.mListBox; + if (listBox.getRowCount() > 1) + this.remove(); + // can't use 'this' as it is destroyed now + listBox.getItemAtIndex(0).updateRemoveButton(); + checkActionsReorder(); + ]]> + </body> + </method> + + <method name="storeFocus"> + <body> + <![CDATA[ + // When this action row is focused, store its index in the parent listbox. + this.mListBox.setAttribute("focusedAction", this.mListBox.getIndexOfItem(this)); + ]]> + </body> + </method> + + </implementation> + </binding> + + <binding id="ruleactiontarget-base"> + <implementation> + <constructor> + <![CDATA[ + if (this.parentNode.hasAttribute('initialActionIndex')) + { + let actionIndex = this.parentNode.getAttribute('initialActionIndex'); + let filterAction = gFilter.getActionAt(actionIndex); + this.parentNode.initWithAction(filterAction); + } + this.parentNode.updateRemoveButton(); + ]]> + </constructor> + </implementation> + </binding> + + <binding id="ruleactiontarget-tag" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base"> + <content> + <xul:menulist class="ruleactionitem"> + <xul:menupopup> + </xul:menupopup> + </xul:menulist> + </content> + + <implementation> + <constructor> + <![CDATA[ + let menuPopup = document.getAnonymousNodes(this)[0].menupopup; + let tagArray = MailServices.tags.getAllTags({}); + for (let i = 0; i < tagArray.length; ++i) + { + var taginfo = tagArray[i]; + var newMenuItem = document.createElement('menuitem'); + newMenuItem.setAttribute('label', taginfo.tag); + newMenuItem.setAttribute('value', taginfo.key); + menuPopup.appendChild(newMenuItem); + } + // propagating a pre-existing hack to make the tag get displayed correctly in the menulist + // now that we've changed the tags for each menu list. We need to use the current selectedIndex + // (if its defined) to handle the case where we were initialized with a filter action already. + var currentItem = document.getAnonymousNodes(this)[0].selectedItem; + document.getAnonymousNodes(this)[0].selectedItem = null; + document.getAnonymousNodes(this)[0].selectedItem = currentItem; + ]]> + </constructor> + </implementation> + </binding> + + <binding id="ruleactiontarget-priority" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base"> + <content> + <xul:menulist class="ruleactionitem"> + <xul:menupopup> + <xul:menuitem value="6" label="&highestPriorityCmd.label;"/> + <xul:menuitem value="5" label="&highPriorityCmd.label;"/> + <xul:menuitem value="4" label="&normalPriorityCmd.label;"/> + <xul:menuitem value="3" label="&lowPriorityCmd.label;"/> + <xul:menuitem value="2" label="&lowestPriorityCmd.label;"/> + </xul:menupopup> + </xul:menulist> + </content> + </binding> + + <binding id="ruleactiontarget-junkscore" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base"> + <content> + <xul:menulist class="ruleactionitem"> + <xul:menupopup> + <xul:menuitem value="100" label="&junk.label;"/> + <xul:menuitem value="0" label="¬Junk.label;"/> + </xul:menupopup> + </xul:menulist> + </content> + </binding> + + <binding id="ruleactiontarget-replyto" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base"> + <content> + <xul:menulist class="ruleactionitem"> + <xul:menupopup> + </xul:menupopup> + </xul:menulist> + </content> + + <implementation> + <constructor> + <![CDATA[ + document.getAnonymousElementByAttribute( + this.parentNode, "class", "ruleactiontype") + .getTemplates(true, document.getAnonymousNodes(this)[0]); + ]]> + </constructor> + </implementation> + </binding> + + <binding id="ruleactiontarget-forwardto" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base"> + <content> + <xul:textbox class="ruleactionitem" flex="1"/> + </content> + </binding> + + <binding id="ruleactiontarget-folder" extends="chrome://messenger/content/searchWidgets.xml#ruleactiontarget-base"> + <content> + <xul:menulist class="ruleactionitem folderMenuItem" + displayformat="verbose" + oncommand="this.parentNode.setPicker(event);"> + <xul:menupopup type="folder" + mode="filing" + class="menulist-menupopup" + showRecent="true" + recentLabel="&recentFolders.label;" + showFileHereLabel="true"/> + </xul:menulist> + </content> + + <implementation> + <constructor> + <![CDATA[ + Components.utils.import("resource:///modules/MailUtils.js", this); + let folder = this.menulist.value ? + this.MailUtils.getFolderForURI(this.menulist.value) : + gFilterList.folder; + // An account folder is not a move/copy target; show "Choose Folder". + folder = folder.isServer ? null : folder; + let menupopup = this.menulist.menupopup; + // The menupopup constructor needs to finish first. + setTimeout(function() { menupopup.selectFolder(folder); }, 0); + ]]> + </constructor> + + <field name="menulist">document.getAnonymousNodes(this)[0]</field> + <method name="setPicker"> + <parameter name="aEvent"/> + <body> + <![CDATA[ + this.menulist.menupopup.selectFolder(aEvent.target._folder); + ]]> + </body> + </method> + </implementation> + </binding> + +</bindings> |