Bug 630759 - Improve attachment list XBL bindings; r=bienvenu, ui-r=bwinton

This commit is contained in:
Jim Porter 2011-08-04 21:55:36 -05:00
Родитель 06e79a0050
Коммит 1e059486ab
25 изменённых файлов: 1049 добавлений и 434 удалений

Просмотреть файл

@ -227,7 +227,7 @@ pref("mail.ui.show.migration.on.upgrade", true);
pref("mail.showCondensedAddresses", true); // show the friendly display name for people I know
// hidden pref for changing how we present attachments in the message pane
pref("mailnews.attachments.display.largeView", false);
pref("mailnews.attachments.display.view", 0);
pref("mail.pane_config.dynamic", 0);
pref("mailnews.reuse_thread_window2", true);
pref("editor.singleLine.pasteNewlines", 4); // substitute commas for new lines in single line text boxes

Просмотреть файл

@ -16,17 +16,50 @@
<!-- dummy widget to force this file to load -->
<binding id="dummy" extends="xul:box"/>
<!-- temporary holding place for horizontal list -->
<binding id="extdescription" extends="chrome://global/content/bindings/listbox.xml#listbox-base">
<binding id="attachmentlist-base" extends="chrome://global/content/bindings/listbox.xml#listbox-base">
<implementation>
<constructor><![CDATA[
this.children.filter(function(aChild) aChild.getAttribute("selected") == "true")
.forEach(this.selectedItems.push, this.selectedItems);
this.children.filter(function(aChild) aChild.getAttribute("selected") == "true")
.forEach(this.selectedItems.push, this.selectedItems);
this.children.filter(function(aChild) !aChild.hasAttribute("context"))
.forEach(function(aChild) aChild.setAttribute("context",
this.getAttribute("itemcontext")), this);
this.sizes = {small: 16, large: 32, tile: 32};
this.messenger = Components.classes["@mozilla.org/messenger;1"]
.createInstance(Components.interfaces.nsIMessenger);
]]></constructor>
<!-- ///////////////// public members ///////////////// -->
<property name="view">
<getter><![CDATA[
return this.getAttribute("view");
]]></getter>
<setter><![CDATA[
this.setAttribute("view", val);
this._setImageSize();
return val;
]]></setter>
</property>
<property name="orient">
<getter><![CDATA[
return this.getAttribute("orient");
]]></getter>
<setter><![CDATA[
// The current item can get messed up when changing orientation.
let curr = this.currentItem;
this.currentItem = null;
this.setAttribute("orient", val);
this.currentItem = curr;
return val;
]]></setter>
</property>
<property name="itemCount" readonly="true"
onget="return this.children.length;"/>
@ -49,20 +82,42 @@
</method>
<method name="getNumberOfVisibleRows">
<body><![CDATA[
var firstItem = this.children[0] || null;
if (!firstItem)
return 0; // nothing to be visible
var itemsPerRow = Math.floor(this.boxObject.width / firstItem.boxObject.width);
var itemsPerCol = Math.floor(this.boxObject.height / firstItem.boxObject.height);
return Math.max(itemsPerRow, 1) * Math.max(itemsPerCol, 1);
return this._itemsPerRow() * this._itemsPerCol();
]]></body>
</method>
<method name="getIndexOfFirstVisibleRow">
<body><![CDATA[
//XXXzeniko unimplementable without a way to scroll
let children = this.children;
if (children.length == 0)
return -1;
// First try to estimate which row is visible, assuming they're all
// the same height.
let box = this.scrollbox;
let estimatedIndex = Math.floor(box.scrollTop /
children[0].boxObject.height);
let offset = children[estimatedIndex].boxObject.screenY -
box.boxObject.screenY;
if (offset > 0) { // We went too far!
for (let i = estimatedIndex - 1; i >= 0; i--) {
if (children[i].boxObject.screenY - box.boxObject.screenY <= 0)
return i;
}
}
else {
for (let i = estimatedIndex; i < this.children.length; i++) {
if (children[i].boxObject.screenY + children[i].boxObject.height -
box.boxObject.screenY > 0)
return i;
}
}
// If we get here, something is very wrong.
dump("Couldn't get index of first visible row for attachmentlist!");
return -1;
]]></body>
</method>
<method name="ensureIndexIsVisible">
<parameter name="index"/>
<body><![CDATA[
@ -72,48 +127,111 @@
<method name="ensureElementIsVisible">
<parameter name="item"/>
<body><![CDATA[
//XXXzeniko unimplementable without a way to scroll
let box = this.scrollbox;
// Are we too far down?
if (item.boxObject.screenY < box.boxObject.screenY)
box.scrollTop = item.boxObject.y - box.boxObject.y;
// ... or not far enough?
else if (item.boxObject.screenY + item.boxObject.height >
box.boxObject.screenY + box.boxObject.height)
box.scrollTop = item.boxObject.y + item.boxObject.height -
box.boxObject.y - box.boxObject.height;
]]></body>
</method>
<method name="scrollToIndex">
<parameter name="index"/>
<body><![CDATA[
//XXXzeniko unimplementable without a way to scroll
let box = this.scrollbox;
let item = this.getItemAtIndex(index);
if (!item)
return;
box.scrollTop = item.boxObject.y - box.boxObject.y;
]]></body>
</method>
<method name="appendItem">
<parameter name="label"/>
<parameter name="value"/>
<parameter name="attachment"/>
<parameter name="name"/>
<body><![CDATA[
// -1 appends due to the way getItemAtIndex is implemented
return this.insertItemAt(-1, label, value);
// -1 appends due to the way getItemAtIndex is implemented.
return this.insertItemAt(-1, attachment, name);
]]></body>
</method>
<method name="insertItemAt">
<parameter name="index"/>
<parameter name="label"/>
<parameter name="value"/>
<parameter name="attachment"/>
<parameter name="name"/>
<body><![CDATA[
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var item = document.createElementNS(XULNS, "descriptionitem");
item.setAttribute("label", label);
let item = this.ownerDocument.createElementNS(XULNS, "attachmentitem");
item.setAttribute("name", name || attachment.name);
if (attachment.size != null && attachment.size != -1)
item.setAttribute("size", this.messenger.formatFileSize(
attachment.size));
// Pick out some nice icons (small and large) for the attachment
if (attachment.contentType == "text/x-moz-deleted") {
let base = "chrome://messenger/skin/icons/";
item.setAttribute("image16", base+"attachment-deleted.png");
item.setAttribute("image32", base+"attachment-deleted-large.png");
}
else {
item.setAttribute("image16", "moz-icon://" + attachment.name +
"?size=16&amp;contentType=" +
attachment.contentType);
item.setAttribute("image32", "moz-icon://" + attachment.name +
"?size=32&amp;contentType=" +
attachment.contentType);
}
item.setAttribute("imagesize", this.sizes[this.getAttribute("view")] || 16);
item.setAttribute("context", this.getAttribute("itemcontext"));
item.attachment = attachment;
this.insertBefore(item, this.getItemAtIndex(index));
return item;
]]></body>
</method>
<method name="scrollOnePage">
<parameter name="direction"/>
<parameter name="direction"/> <!-- Must be -1 or 1 -->
<body><![CDATA[
return direction * this.getNumberOfVisibleRows();
let pageOffset = this.getNumberOfVisibleRows() * direction;
// skip over invisible elements - the user won't care about them
for (let i = 0; i != pageOffset; i += direction) {
let item = this.getItemAtIndex(this.currentIndex + i);
if (item && !this._canUserSelect(item))
pageOffset += direction;
}
let newTop = this.getIndexOfFirstVisibleRow() + pageOffset;
if (direction == 1) {
let maxTop = this.getRowCount() - this.getNumberOfVisibleRows();
for (let i = this.getRowCount(); i >= 0 && i > maxTop; i--) {
let item = this.getItemAtIndex(i);
if (item && !this._canUserSelect(item))
maxTop--;
}
if (newTop >= maxTop)
newTop = maxTop;
}
if (newTop < 0)
newTop = 0;
this.scrollToIndex(newTop);
return pageOffset;
]]></body>
</method>
<!-- Get the preferred height (the height that would allow us to fit
everything without scrollbars) of the attachmentlist's boxObject. -->
<property name="preferredHeight" readonly="true"
onget="return this.scrollbox.scrollHeight - this.scrollbox.clientHeight + this.boxObject.height;"/>
<!-- ///////////////// private members ///////////////// -->
<property name="children" readonly="true"
onget="return Array.slice(this.getElementsByTagName('descriptionitem'));"/>
onget="return Array.slice(this.getElementsByTagName('attachmentitem'));"/>
<property name="scrollbox" readonly="true"
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'scrollbox');"/>
<method name="_fireOnSelect">
<body><![CDATA[
@ -124,17 +242,59 @@
}
]]></body>
</method>
<method name="_itemsPerRow">
<body><![CDATA[
let firstItem = this.children[0] || null;
if (!firstItem)
return 0; // nothing to be visible
let itemsPerRow = Math.floor(this.scrollbox.clientWidth /
firstItem.boxObject.width);
return Math.max(itemsPerRow, 1);
]]></body>
</method>
<method name="_itemsPerCol">
<body><![CDATA[
let firstItem = this.children[0] || null;
if (!firstItem)
return 0; // nothing to be visible
let itemsPerCol = Math.floor(this.scrollbox.clientHeight /
firstItem.boxObject.height);
return Math.max(itemsPerCol, 1);
]]></body>
</method>
<method name="_setImageSize">
<body><![CDATA[
let children = this.children;
let size = this.sizes[this.view] || 16;
for (let i = 0; i < children.length; i++)
children[i].imageSize = size;
]]></body>
</method>
</implementation>
<handlers>
<handler event="keypress" keycode="VK_LEFT" modifiers="control shift any"
action="this.moveByOffset(-1, !event.ctrlKey, event.shiftKey);"
phase="target" preventdefault="true"/>
<handler event="keypress" keycode="VK_RIGHT" modifiers="control shift any"
action="this.moveByOffset(1, !event.ctrlKey, event.shiftKey);"
<!-- The spacebar should work just like the arrow keys, except that the
focused element doesn't change, so use moveByOffset here. -->
<handler event="keypress" key=" " modifiers="control shift any"
action="this.moveByOffset(0, !event.ctrlKey, event.shiftKey);"
phase="target" preventdefault="true"/>
<handler event="keypress" keycode="VK_RETURN"><![CDATA[
if (this.currentItem) {
this.addItemToSelection(this.currentItem);
let event = document.createEvent("Events");
event.initEvent("command", true, true);
this.currentItem.dispatchEvent(event);
}
]]></handler>
<handler event="click" button="0" phase="target"><![CDATA[
if (this.selType != "multiple" || (!event.ctrlKey && !event.shiftKey && !event.metaKey))
if (this.selType != "multiple" || (!event.ctrlKey && !event.shiftKey &&
!event.metaKey))
this.clearSelection();
]]></handler>
<!-- make sure we keep the focus... -->
@ -143,21 +303,93 @@
</handlers>
</binding>
<binding id="descriptionitem" extends="chrome://global/content/bindings/listbox.xml#listitem">
<binding id="attachmentlist-horizontal" extends="chrome://messenger/content/mailWidgets.xml#attachmentlist-base">
<content>
<xul:hbox class="attachmentBox" xbl:inherits="orient" align="start">
<xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
</xul:hbox>
<xul:scrollbox flex="1" anonid="scrollbox" style="overflow: auto;">
<xul:hbox flex="1" class="attachmentlist-wrapper">
<children includes="attachmentitem"/>
</xul:hbox>
</xul:scrollbox>
</content>
<handlers>
<handler event="keypress" keycode="VK_LEFT" modifiers="control shift any"
action="this.moveByOffset(-1, !event.ctrlKey, event.shiftKey);"
phase="target" preventdefault="true"/>
<handler event="keypress" keycode="VK_RIGHT" modifiers="control shift any"
action="this.moveByOffset(1, !event.ctrlKey, event.shiftKey);"
phase="target" preventdefault="true"/>
<handler event="keypress" keycode="VK_UP" modifiers="control shift any"
action="this.moveByOffset(-this._itemsPerRow(), !event.ctrlKey, event.shiftKey);"
phase="target" preventdefault="true"/>
<handler event="keypress" keycode="VK_DOWN" modifiers="control shift any"
action="this.moveByOffset(this._itemsPerRow(), !event.ctrlKey, event.shiftKey);"
phase="target" preventdefault="true"/>
</handlers>
</binding>
<binding id="attachmentlist-vertical" extends="chrome://messenger/content/mailWidgets.xml#attachmentlist-base">
<content>
<xul:scrollbox orient="vertical" flex="1" anonid="scrollbox"
style="overflow: auto;">
<children includes="attachmentitem"/>
</xul:scrollbox>
</content>
</binding>
<binding id="descriptionitem-iconic" extends="chrome://global/content/bindings/listbox.xml#listitem">
<binding id="attachmentitem" extends="chrome://global/content/bindings/listbox.xml#listitem">
<implementation>
<constructor><![CDATA[
this._updateImage();
]]></constructor>
<property name="imageSize">
<getter><![CDATA[
return this.getAttribute("imagesize");
]]></getter>
<setter><![CDATA[
this.setAttribute("imagesize", val);
this._updateImage();
return val;
]]></setter>
</property>
<method name="_updateImage">
<body><![CDATA[
if (!this.hasAttribute("image")) {
let icon = document.getAnonymousElementByAttribute(this, "anonid",
"icon");
let attr = "image"+this.imageSize;
if (this.hasAttribute(attr))
icon.setAttribute("src", this.getAttribute(attr));
}
]]></body>
</method>
</implementation>
<!-- Below, we want the name label to flex but not be any bigger than
necessary, so add a spacer with a huge flex value. -->
<content>
<xul:hbox class="attachmentBox" xbl:inherits="orient" align="center">
<xul:image class="descriptioncell-icon" xbl:inherits="src=image"/>
<xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
<xul:hbox class="attachmentcell-content" flex="1">
<xul:hbox align="center">
<xul:image class="attachmentcell-icon" anonid="icon"
xbl:inherits="src=image"/>
</xul:hbox>
<xul:hbox class="attachmentcell-text" flex="1">
<xul:hbox class="attachmentcell-nameselection" flex="1">
<xul:label class="attachmentcell-name" xbl:inherits="value=name"
flex="1" crop="center"/>
</xul:hbox>
<xul:spacer flex="99999"/>
<xul:label class="attachmentcell-size" xbl:inherits="value=size"/>
</xul:hbox>
</xul:hbox>
</content>
<handlers>
<handler event="click" button="0" clickcount="2"><![CDATA[
let event = document.createEvent("Events");
event.initEvent("command", true, true);
this.dispatchEvent(event);
]]></handler>
</handlers>
</binding>
<!-- Message Pane Widgets -->

Просмотреть файл

@ -154,6 +154,7 @@
</popupset>
<menupopup id="attachmentListContext"/>
<menupopup id="attachmentItemContext"/>
<menupopup id="header-toolbar-context-menu"/>
<menupopup id="attachment-toolbar-context-menu"/>
<menupopup id="copyUrlPopup"/>

Просмотреть файл

@ -43,18 +43,69 @@
/* ::::: mail xbl bindings ::::: */
description[selectable="true"] {
-moz-binding: url("chrome://messenger/content/mailWidgets.xml#extdescription");
/* attachment list styles */
attachmentlist {
-moz-appearance: listbox;
-moz-user-focus: normal;
}
descriptionitem {
-moz-binding: url("chrome://messenger/content/mailWidgets.xml#descriptionitem");
attachmentlist[orient="horizontal"] {
-moz-binding: url("chrome://messenger/content/mailWidgets.xml#attachmentlist-horizontal");
}
.descriptionitem-iconic {
-moz-binding: url("chrome://messenger/content/mailWidgets.xml#descriptionitem-iconic");
attachmentlist[orient="vertical"] {
-moz-binding: url("chrome://messenger/content/mailWidgets.xml#attachmentlist-vertical");
}
.attachmentlist-wrapper {
display: block;
margin: 0;
padding: 0;
line-height: 0;
}
attachmentitem {
-moz-binding: url("chrome://messenger/content/mailWidgets.xml#attachmentitem");
}
.attachmentcell-content {
-moz-box-orient: horizontal;
}
.attachmentcell-text {
-moz-box-orient: horizontal;
}
attachmentitem {
width: 15em;
}
attachmentlist[view="large"] .attachmentcell-content {
-moz-box-orient: horizontal;
}
attachmentlist[view="large"] .attachmentcell-text {
-moz-box-align: start;
-moz-box-orient: vertical;
}
attachmentlist[view="tile"] .attachmentcell-content {
-moz-box-align: center;
-moz-box-orient: vertical;
}
attachmentlist[view="tile"] .attachmentcell-text {
-moz-box-align: center;
-moz-box-orient: vertical;
}
attachmentlist[view="tile"] > attachmentitem {
width: 9em;
}
/* message header widgets */
mail-messageid {
-moz-binding: url("chrome://messenger/content/mailWidgets.xml#mail-messageid");
}

Просмотреть файл

@ -164,6 +164,7 @@
<menupopup id="mailContext"/>
<menupopup id="folderPaneContext"/>
<menupopup id="attachmentListContext"/>
<menupopup id="attachmentItemContext"/>
<menupopup id="header-toolbar-context-menu"/>
<menupopup id="attachment-toolbar-context-menu"/>
<menupopup id="copyUrlPopup"/>

Просмотреть файл

@ -1774,98 +1774,83 @@ function ContentTypeIsSMIME(contentType)
}
/**
* Set up the attachment context menu, showing or hiding the appropriate menu
* items.
* Set up the attachment item context menu, showing or hiding the appropriate
* menu items.
*/
function onShowAttachmentContextMenu()
function onShowAttachmentItemContextMenu()
{
var attachmentList = document.getElementById('attachmentList');
var attachmentName = document.getElementById('attachmentName');
var contextMenu = document.getElementById('attachmentListContext');
var openMenu = document.getElementById('context-openAttachment');
var saveMenu = document.getElementById('context-saveAttachment');
var menuSeparator = document.getElementById('context-menu-separator');
var detachMenu = document.getElementById('context-detachAttachment');
var deleteMenu = document.getElementById('context-deleteAttachment');
var openAllMenu = document.getElementById('context-openAllAttachments');
var saveAllMenu = document.getElementById('context-saveAllAttachments');
var menuSeparatorAll = document.getElementById('context-menu-separator-all');
var detachAllMenu = document.getElementById('context-detachAllAttachments');
var deleteAllMenu = document.getElementById('context-deleteAllAttachments');
let attachmentList = document.getElementById("attachmentList");
let attachmentName = document.getElementById("attachmentName");
let contextMenu = document.getElementById("attachmentItemContext");
let openMenu = document.getElementById("context-openAttachment");
let saveMenu = document.getElementById("context-saveAttachment");
let detachMenu = document.getElementById("context-detachAttachment");
let deleteMenu = document.getElementById("context-deleteAttachment");
// If we opened the context menu from the attachmentName label, just grab
// the first (and only) attachment as our "selected" attachments.
var selectedAttachments;
if (contextMenu.triggerNode == attachmentName) {
selectedAttachments = [attachmentList.getItemAtIndex(0).attachment];
attachmentName.setAttribute('selected', true);
attachmentName.setAttribute("selected", true);
}
else
selectedAttachments = [item.attachment for each([, item] in
Iterator(attachmentList.selectedItems))];
contextMenu.attachments = selectedAttachments;
var selectNone = selectedAttachments.length == 0;
var allSelectedDetached = selectedAttachments.every(function(attachment) {
return attachment.isExternalAttachment;
});
var allSelectedDeleted = selectedAttachments.every(function(attachment) {
return !attachment.hasFile;
});
var canDetachSelected = CanDetachAttachments() && !allSelectedDetached &&
!allSelectedDeleted;
openMenu.hidden = selectNone;
saveMenu.hidden = selectNone;
menuSeparator.hidden = selectNone;
detachMenu.hidden = selectNone;
deleteMenu.hidden = selectNone;
openAllMenu.hidden = !selectNone;
saveAllMenu.hidden = !selectNone;
menuSeparatorAll.hidden = !selectNone;
detachAllMenu.hidden = !selectNone;
deleteAllMenu.hidden = !selectNone;
if (!selectNone)
{
var allSelectedDetached = selectedAttachments.every(function(attachment) {
return attachment.isExternalAttachment;
});
var allSelectedDeleted = selectedAttachments.every(function(attachment) {
return !attachment.hasFile;
});
var canDetachSelected = CanDetachAttachments() && !allSelectedDetached &&
!allSelectedDeleted;
openMenu.disabled = allSelectedDeleted;
saveMenu.disabled = allSelectedDeleted;
detachMenu.disabled = !canDetachSelected;
deleteMenu.disabled = !canDetachSelected;
}
else
{
var allDetached = currentAttachments.every(function(attachment) {
return attachment.isExternalAttachment;
});
var allDeleted = currentAttachments.every(function(attachment) {
return !attachment.hasFile;
});
var canDetachAll = CanDetachAttachments() && !allDetached && !allDeleted;
saveAllMenu.disabled = allDeleted;
openAllMenu.disabled = allDeleted;
detachAllMenu.disabled = !canDetachAll;
deleteAllMenu.disabled = !canDetachAll;
}
openMenu.disabled = allSelectedDeleted;
saveMenu.disabled = allSelectedDeleted;
detachMenu.disabled = !canDetachSelected;
deleteMenu.disabled = !canDetachSelected;
}
/**
* Close the attachment context menu, performing any cleanup as necessary.
* Close the attachment item context menu, performing any cleanup as necessary.
*/
function onHideAttachmentContextMenu()
function onHideAttachmentItemContextMenu()
{
let attachmentName = document.getElementById('attachmentName');
let contextMenu = document.getElementById('attachmentListContext');
let attachmentName = document.getElementById("attachmentName");
let contextMenu = document.getElementById("attachmentListContext");
// If we opened the context menu from the attachmentName label, we need to
// get rid of the "selected" attribute.
if (contextMenu.triggerNode == attachmentName)
attachmentName.removeAttribute('selected');
attachmentName.removeAttribute("selected");
}
/**
* Set up the attachment list context menu, showing or hiding the appropriate
* menu items.
*/
function onShowAttachmentListContextMenu()
{
var openAllMenu = document.getElementById("context-openAllAttachments");
var saveAllMenu = document.getElementById("context-saveAllAttachments");
var detachAllMenu = document.getElementById("context-detachAllAttachments");
var deleteAllMenu = document.getElementById("context-deleteAllAttachments");
var allDetached = currentAttachments.every(function(attachment) {
return attachment.isExternalAttachment;
});
var allDeleted = currentAttachments.every(function(attachment) {
return !attachment.hasFile;
});
var canDetachAll = CanDetachAttachments() && !allDetached && !allDeleted;
saveAllMenu.disabled = allDeleted;
openAllMenu.disabled = allDeleted;
detachAllMenu.disabled = !canDetachAll;
deleteAllMenu.disabled = !canDetachAll;
}
/**
@ -1923,20 +1908,15 @@ function MessageIdClick(node, event)
}
}
// this is our onclick handler for the attachment list.
// A double click in a listitem simulates "opening" the attachment....
function attachmentListClick(event)
/**
* This is our oncommand handler for the attachment list items. A double click
* or enter press in an attachmentitem simulates "opening" the attachment.
*
* @param event the event object
*/
function attachmentItemCommand(event)
{
// we only care about button 0 (left click) events
if (event.button != 0)
return;
if (event.detail == 2) // double click
{
var target = event.target;
if (target.localName == "descriptionitem")
target.attachment.open();
}
HandleSelectedAttachments("open");
}
function createAttachmentDisplayName(aAttachment)
@ -1949,65 +1929,106 @@ function createAttachmentDisplayName(aAttachment)
return aAttachment.name.trimRight();
}
var AttachmentListController =
{
supportsCommand: function(command)
{
switch (command)
{
case "cmd_selectAll":
case "cmd_delete":
case "cmd_shiftDelete":
case "button_delete":
case "cmd_saveAsFile":
return true;
default:
return false;
}
},
isCommandEnabled: function(command)
{
switch (command)
{
case "cmd_selectAll":
case "cmd_delete":
case "cmd_shiftDelete":
case "button_delete":
case "cmd_saveAsFile":
return true;
default:
return false;
}
},
doCommand: function(command)
{
// If the user invoked a key short cut then it is possible that we got here
// for a command which is really disabled. kick out if the command should
// be disabled.
if (!this.isCommandEnabled(command)) return;
var attachmentList = document.getElementById('attachmentList');
switch (command)
{
case "cmd_selectAll":
attachmentList.selectAll();
return;
case "cmd_delete":
case "cmd_shiftDelete":
case "button_delete":
HandleSelectedAttachments('delete');
return;
case "cmd_saveAsFile":
HandleSelectedAttachments('saveAs');
return;
}
},
onEvent: function(event)
{}
};
function displayAttachmentsForExpandedView()
{
var bundle = document.getElementById("bundle_messenger");
var numAttachments = currentAttachments.length;
var totalSize = 0;
var attachmentView = document.getElementById('attachmentView');
var attachmentSplitter = document.getElementById('attachment-splitter');
var attachmentView = document.getElementById("attachmentView");
var attachmentSplitter = document.getElementById("attachment-splitter");
if (numAttachments <= 0)
{
if (numAttachments <= 0) {
attachmentView.collapsed = true;
attachmentSplitter.collapsed = true;
}
else if (!gBuildAttachmentsForCurrentMsg)
{
else if (!gBuildAttachmentsForCurrentMsg) {
attachmentView.collapsed = false;
var attachmentList = document.getElementById('attachmentList');
var attachmentList = document.getElementById("attachmentList");
var showLargeAttView = Components.classes["@mozilla.org/preferences-service;1"]
var viewMode = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch2)
.getBoolPref("mailnews.attachments.display.largeView")
attachmentList.setAttribute("largeView", showLargeAttView);
.getIntPref("mailnews.attachments.display.view");
var views = ["small", "large", "tile"];
attachmentList.view = views[viewMode];
attachmentList.controllers.appendController(AttachmentListController);
toggleAttachmentList(false);
var unknownSize = false;
for each (let [, attachment] in Iterator(currentAttachments))
{
for each (let [, attachment] in Iterator(currentAttachments)) {
// Create a new attachment widget
var displayName = createAttachmentDisplayName(attachment);
var item;
if (attachment.size != null) {
var size = messenger.formatFileSize(attachment.size);
var nameAndSize = bundle.getFormattedString("attachmentNameAndSize",
[displayName, size]);
item = attachmentList.appendItem(nameAndSize);
totalSize += attachment.size;
}
else {
if (!attachment.isDeleted)
unknownSize = true;
item = attachmentList.appendItem(displayName);
}
item.setAttribute("class", "descriptionitem-iconic");
setApplicationIconForAttachment(attachment, item, showLargeAttView);
var item = attachmentList.appendItem(attachment, displayName);
item.setAttribute("tooltiptext", attachment.name);
item.setAttribute("context", "attachmentListContext");
item.addEventListener("command", attachmentItemCommand, false);
item.attachment = attachment;
item.setAttribute("attachmentUrl", attachment.url);
item.setAttribute("attachmentContentType", attachment.contentType);
item.setAttribute("attachmentUri", attachment.uri);
item.setAttribute("attachmentSize", attachment.size);
attachmentList.appendChild(item);
} // for each attachment
if (attachment.size !== null)
totalSize += attachment.size;
else if (!attachment.isDeleted)
unknownSize = true;
}
// Show the appropriate toolbar button and label based on the number of
// attachments.
@ -2079,62 +2100,49 @@ function updateSaveAllAttachmentsButton()
*/
function toggleAttachmentList(expanded)
{
var attachmentToggle = document.getElementById("attachmentToggle");
var attachmentView = document.getElementById("attachmentView");
var attachmentSplitter = document.getElementById("attachment-splitter");
var attachmentListWrapper = document.getElementById("attachmentListWrapper");
var attachmentToggle = document.getElementById("attachmentToggle");
var attachmentView = document.getElementById("attachmentView");
var attachmentList = document.getElementById("attachmentList");
var attachmentSplitter = document.getElementById("attachment-splitter");
if (expanded === undefined)
expanded = !attachmentToggle.checked;
attachmentToggle.checked = expanded;
if (expanded) {
attachmentListWrapper.collapsed = false;
attachmentList.collapsed = false;
attachmentSplitter.collapsed = false;
var attachmentHeight = attachmentView.boxObject.height;
var attachmentHeight = attachmentView.boxObject.height -
attachmentList.boxObject.height + attachmentList.preferredHeight;
// If the attachments box takes up too much of the message pane, downsize:
var maxAttachmentHeight = document.getElementById("messagepanebox")
.boxObject.height / 4;
attachmentListWrapper.setAttribute("attachmentOverflow", "true");
attachmentView.setAttribute("height", Math.min(attachmentHeight,
maxAttachmentHeight));
attachmentView.setAttribute("maxheight", attachmentHeight);
}
else {
attachmentListWrapper.collapsed = true;
attachmentList.collapsed = true;
attachmentSplitter.collapsed = true;
attachmentView.removeAttribute("height");
attachmentView.removeAttribute("maxheight");
// Switch overflow off so that when we expand again we can get the
// preferred size. (Doing this when expanding hits a race condition.)
attachmentListWrapper.setAttribute("attachmentOverflow", "false");
}
}
/**
* Show a nice icon next to the attachment.
* Pick out a nice icon for the attachment.
* @param attachment the nsIMsgAttachment object to show icon for
* @param listitem the listitem currently showing the attachment
* @param largeView boolean value: 32x32 vs. 16x16 size icon
*/
function setApplicationIconForAttachment(attachment, listitem, largeView)
function getIconForAttachment(attachment)
{
// Show a nice icon next to it the attachment.
if (attachment.isDeleted)
{
let fn = largeView ? "attachment-deleted-large.png" : "attachment-deleted.png";
listitem.setAttribute("image", "chrome://messenger/skin/icons/"+fn);
}
return "chrome://messenger/skin/icon/attachment-deleted.png";
else
{
let iconSize = largeView ? 32 : 16;
listitem.setAttribute("image", "moz-icon://" + attachment.name + "?size=" +
iconSize + "&contentType=" + attachment.contentType);
}
return "moz-icon://" + attachment.name + "?size=16&amp;contentType=" +
attachment.contentType;
}
// Public method called when we create the attachments file menu
@ -2206,7 +2214,7 @@ function addAttachmentToPopup(popup, attachment, attachmentIndex)
// Insert the item just before the separator. The separator is the 2nd to
// last element in the popup.
item.setAttribute('class', 'menu-iconic');
setApplicationIconForAttachment(attachment,item, false);
item.setAttribute('image', getIconForAttachment(attachment));
var numItemsInPopup = popup.childNodes.length;
// find the separator
@ -2301,7 +2309,7 @@ function HandleSelectedAttachments(action)
/**
* Perform an action on multiple attachments (e.g. open or save)
*
* @param attachments an array of attachment objects to work with
* @param attachments an array of AttachmentInfo objects to work with
* @param action one of "open", "save", "saveAs", "detach", or "delete"
*/
function HandleMultipleAttachments(attachments, action)
@ -2417,7 +2425,7 @@ var attachmentListDNDObserver = {
{
var target = aEvent.target;
if (target.localName == "descriptionitem")
if (target.localName == "attachmentitem")
aAttachmentData.data = CreateAttachmentTransferData(target.attachment);
}
};

Просмотреть файл

@ -43,6 +43,7 @@
]>
<?xml-stylesheet href="chrome://messenger/skin/messageHeader.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/attachmentList.css" type="text/css"?>
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
@ -73,9 +74,9 @@
CopyMessageId(messageId);"/>
</menupopup>
<menupopup id="attachmentListContext"
onpopupshowing="return onShowAttachmentContextMenu();"
onpopuphiding="return onHideAttachmentContextMenu();">
<menupopup id="attachmentItemContext"
onpopupshowing="return onShowAttachmentItemContextMenu();"
onpopuphiding="return onHideAttachmentItemContextMenu();">
<menuitem id="context-openAttachment"
label="&openAttachmentCmd.label;"
accesskey="&openAttachmentCmd.accesskey;"
@ -93,6 +94,10 @@
label="&deleteAttachmentCmd.label;"
accesskey="&deleteAttachmentCmd.accesskey;"
oncommand="HandleMultipleAttachments(this.parentNode.attachments, 'delete');"/>
</menupopup>
<menupopup id="attachmentListContext"
onpopupshowing="return onShowAttachmentListContextMenu(event);">
<menuitem id="context-openAllAttachments"
label="&openAllAttachmentsCmd.label;"
accesskey="&openAllAttachmentsCmd.accesskey;"
@ -512,7 +517,7 @@
<image id="attachmentIcon"/>
<label id="attachmentCount"/>
<label id="attachmentName" crop="center" flex="1"
context="attachmentListContext"
context="attachmentItemContext"
onclick="if (event.button == 0) { HandleAllAttachments('open'); RestoreFocusAfterHdrButton(); }"
ondraggesture="nsDragAndDrop.startDrag(event,attachmentNameDNDObserver);"/>
<label id="attachmentSize"/>
@ -593,14 +598,11 @@
defaultset="attachmentSaveAll"/>
</toolbox>
</hbox>
<box id="attachmentListWrapper" flex="1" collapsed="true">
<description selectable="true" id="attachmentList" flex="1"
seltype="multiple" context="attachmentListContext"
onclick="attachmentListClick(event);"
ondraggesture="nsDragAndDrop.startDrag(event,attachmentListDNDObserver);"
ondragover="nsDragAndDrop.dragOver(event, attachmentListDNDObserver);">
</description>
</box>
<attachmentlist orient="horizontal" id="attachmentList" flex="1"
seltype="multiple" context="attachmentListContext"
itemcontext="attachmentItemContext"
ondraggesture="nsDragAndDrop.startDrag(event,attachmentListDNDObserver);"
ondragover="nsDragAndDrop.dragOver(event, attachmentListDNDObserver);"/>
</vbox>
</overlay>

Просмотреть файл

@ -2936,27 +2936,17 @@ function AddUrlAttachment(attachment)
attachment.name = gComposeBundle.getString("partAttachmentSafeName");
var bucket = document.getElementById("attachmentBucket");
var item;
var item = bucket.appendItem(attachment);
if (attachment.size != -1)
{
var size = gMessenger.formatFileSize(attachment.size);
var nameAndSize = gComposeBundle.getFormattedString(
"attachmentNameAndSize", [attachment.name, size]);
item = bucket.appendItem(nameAndSize, "");
gAttachmentsSize += attachment.size;
}
else
item = bucket.appendItem(attachment.name, "");
item.attachment = attachment; // Full attachment object stored here.
try {
item.setAttribute("tooltiptext", decodeURI(attachment.url));
}
catch(e) {
item.setAttribute("tooltiptext", attachment.url);
}
item.setAttribute("class", "listitem-iconic");
item.setAttribute("crop", "center");
item.addEventListener("command", OpenSelectedAttachment, false);
// For local file urls, we are better off using the full file url because
// moz-icon will actually resolve the file url and get the right icon from
@ -3520,13 +3510,9 @@ function subjectKeyPress(event)
function AttachmentBucketClicked(event)
{
if (event.button != 0)
return;
if (event.originalTarget.localName == "listboxbody")
let boundTarget = document.getBindingParent(event.originalTarget);
if (event.button == 0 && boundTarget.localName == "scrollbox")
goDoCommand('cmd_attachFile');
else if (event.originalTarget.localName == "listitem" && event.detail == 2)
OpenSelectedAttachment();
}
// we can drag and drop addresses, files, messages and urls into the compose envelope

Просмотреть файл

@ -42,6 +42,7 @@
<?xml-stylesheet href="chrome://messenger/skin/messengercompose/messengercompose.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/folderMenus.css" type="text/css"?>
<?xml-stylesheet href="chrome://messenger/skin/attachmentList.css" type="text/css"?>
<?xul-overlay href="chrome://editor/content/editorOverlay.xul"?>
#ifdef XP_MACOSX
<?xul-overlay href="chrome://messenger/content/macMenuOverlay.xul"?>
@ -312,14 +313,35 @@
</menupopup>
<menupopup id="msgComposeAttachmentContext" onpopupshowing="updateEditItems();">
<menuitem label="&openAttachment.label;" accesskey="&openAttachment.accesskey;" command="cmd_openAttachment"/>
<menuitem label="&removeAttachment.label;" accesskey="&removeAttachment.accesskey;" command="cmd_delete"/>
<menuitem label="&renameAttachment.label;" accesskey="&renameAttachment.accesskey;" command="cmd_renameAttachment"/>
<menuitem label="&selectAll.label;" accesskey="&selectAll.accesskey;" command="cmd_selectAll"/>
<menupopup id="msgComposeAttachmentItemContext"
onpopupshowing="updateEditItems();">
<menuitem label="&openAttachment.label;"
accesskey="&openAttachment.accesskey;"
command="cmd_openAttachment"/>
<menuitem label="&removeAttachment.label;"
accesskey="&removeAttachment.accesskey;"
command="cmd_delete"/>
<menuitem label="&renameAttachment.label;"
accesskey="&renameAttachment.accesskey;"
command="cmd_renameAttachment"/>
<menuseparator/>
<menuitem label="&attachFile.label;" accesskey="&attachFile.accesskey;" command="cmd_attachFile"/>
<menuitem label="&attachPage.label;" accesskey="&attachPage.accesskey;" command="cmd_attachPage"/>
<menuitem label="&selectAll.label;"
accesskey="&selectAll.accesskey;"
command="cmd_selectAll"/>
</menupopup>
<menupopup id="msgComposeAttachmentListContext"
onpopupshowing="updateEditItems();">
<menuitem label="&selectAll.label;"
accesskey="&selectAll.accesskey;"
command="cmd_selectAll"/>
<menuseparator/>
<menuitem label="&attachFile.label;"
accesskey="&attachFile.accesskey;"
command="cmd_attachFile"/>
<menuitem label="&attachPage.label;"
accesskey="&attachPage.accesskey;"
command="cmd_attachPage"/>
</menupopup>
<menupopup id="toolbar-context-menu"
@ -755,12 +777,13 @@
crop="right" accesskey="&attachments.accesskey;"/>
<label id="attachmentBucketSize"/>
</hbox>
<listbox seltype="multiple" id="attachmentBucket" flex="1" rows="4"
tabindex="0"
context="msgComposeAttachmentContext"
onkeypress="if (event.keyCode == 8 || event.keyCode == 46) RemoveSelectedAttachment();"
onclick="AttachmentBucketClicked(event);"
ondraggesture="nsDragAndDrop.startDrag(event, attachmentBucketDNDObserver);"/>
<attachmentlist orient="vertical" id="attachmentBucket"
seltype="multiple" flex="1" height="0" tabindex="0"
context="msgComposeAttachmentListContext"
itemcontext="msgComposeAttachmentItemContext"
onkeypress="if (event.keyCode == 8 || event.keyCode == 46) RemoveSelectedAttachment();"
onclick="AttachmentBucketClicked(event);"
ondraggesture="nsDragAndDrop.startDrag(event, attachmentBucketDNDObserver);"/>
</vbox>
</hbox>
</toolbar>

Просмотреть файл

@ -218,16 +218,16 @@ function setupModule(module) {
*/
function check_attachment_size(index, expectedSize) {
let list = mc.e('attachmentList');
let node = list.getElementsByTagName('descriptionitem')[index];
let node = list.getElementsByTagName('attachmentitem')[index];
// First, let's check that the 'attachmentSize' attribute is correct
let size = parseInt(node.getAttribute('attachmentSize'));
// First, let's check that the attachment size is correct
let size = node.attachment.size;
if (Math.abs(size - expectedSize) > epsilon)
throw new Error('Reported attachment size ('+size+') not within epsilon ' +
'of actual attachment size ('+expectedSize+')');
// Next, make sure that the formatted size in the label is correct
let formattedSize = /\((.*?)\)$/.exec(node.getAttribute('label'))[1];
let formattedSize = node.getAttribute('size');
let expectedFormattedSize = messenger.formatFileSize(size);
if (formattedSize != expectedFormattedSize)
throw new Error('Formatted attachment size ('+formattedSize+') does not ' +
@ -240,13 +240,13 @@ function check_attachment_size(index, expectedSize) {
*/
function check_no_attachment_size(index) {
let list = mc.e('attachmentList');
let node = list.getElementsByTagName('descriptionitem')[index];
let node = list.getElementsByTagName('attachmentitem')[index];
if (node.getAttribute('attachmentSize') != '')
if (node.attachment.size != null)
throw new Error('attachmentSize attribute of deleted attachment should ' +
'be null!');
if (/\((.*?)\)$/.exec(node.getAttribute('label')))
if (node.getAttribute('size') != '')
throw new Error('Attachment size should not be displayed!');
}
@ -258,7 +258,7 @@ function check_no_attachment_size(index) {
*/
function check_total_attachment_size(count, expectedSize, exact) {
let list = mc.e('attachmentList');
let nodes = list.getElementsByTagName('descriptionitem');
let nodes = list.getElementsByTagName('attachmentitem');
let sizeNode = mc.e('attachmentSize');
if (nodes.length != count)
@ -266,7 +266,7 @@ function check_total_attachment_size(count, expectedSize, exact) {
let size = 0;
for (let i = 0; i < nodes.length; i++) {
let currSize = parseInt(nodes[i].getAttribute('attachmentSize'));
let currSize = nodes[i].attachment.size;
if (!isNaN(currSize))
size += currSize;
}

Просмотреть файл

@ -69,6 +69,8 @@ const binaryAttachment = textAttachment;
var setupModule = function (module) {
let fdh = collector.getModule('folder-display-helpers');
fdh.installInto(module);
let wh = collector.getModule('window-helpers');
wh.installInto(module);
let composeHelper = collector.getModule('compose-helpers');
composeHelper.installInto(module);
let wh = collector.getModule('window-helpers');
@ -137,8 +139,8 @@ function test_attachment_name_click() {
// Ensure the context menu appears when right-clicking the attachment name
mc.rightClick(mc.eid("attachmentName"));
wait_for_popup_to_open(mc.e("attachmentListContext"));
close_popup(mc, mc.eid("attachmentListContext"));
wait_for_popup_to_open(mc.e("attachmentItemContext"));
close_popup(mc, mc.eid("attachmentItemContext"));
}
function test_attachment_list_expansion() {
@ -147,24 +149,28 @@ function test_attachment_list_expansion() {
select_click_row(1);
assert_selected_and_displayed(1);
assert_true(mc.e("attachmentListWrapper").collapsed,
"Attachment list should start out collapsed!");
let attachmentList = mc.e("attachmentList");
let attachmentToggle = mc.eid("attachmentToggle");
let attachmentBar = mc.eid("attachmentBar");
mc.click(mc.eid("attachmentToggle"));
assert_true(!mc.e("attachmentListWrapper").collapsed,
"Attachment list should be expanded after clicking twisty!");
assert_true(attachmentList.collapsed, "Attachment list should start out " +
"collapsed!");
mc.click(mc.eid("attachmentToggle"));
assert_true(mc.e("attachmentListWrapper").collapsed,
"Attachment list should be collapsed after clicking twisty again!");
mc.click(attachmentToggle);
assert_true(!attachmentList.collapsed, "Attachment list should be expanded " +
"after clicking twisty!");
mc.click(mc.eid("attachmentBar"));
assert_true(!mc.e("attachmentListWrapper").collapsed,
"Attachment list should be expanded after clicking bar!");
mc.click(attachmentToggle);
assert_true(attachmentList.collapsed, "Attachment list should be collapsed " +
"after clicking twisty again!");
mc.click(mc.eid("attachmentBar"));
assert_true(mc.e("attachmentListWrapper").collapsed,
"Attachment list should be collapsed after clicking bar again!");
mc.click(attachmentBar);
assert_true(!attachmentList.collapsed, "Attachment list should be expanded " +
"after clicking bar!");
mc.click(attachmentBar);
assert_true(attachmentList.collapsed, "Attachment list should be collapsed " +
"after clicking bar again!");
}
function test_selected_attachments_are_cleared() {
@ -183,7 +189,7 @@ function test_selected_attachments_are_cleared() {
// We can just click on the first element, but the second one needs a
// ctrl-click (or cmd-click for those Mac-heads among us).
mc.click(new elib.Elem(attachmentList.children[0]));
mc.click(new elib.Elem(attachmentList.children[0]), 5, 5);
EventUtils.synthesizeMouse(attachmentList.children[1], 5, 5,
{accelKey: true}, mc.window);
@ -232,10 +238,55 @@ function test_attachment_toolbar_customize() {
add_to_toolbar(mc.e("attachment-view-toolbar"), "attachmentSaveAll");
}
function test_select_all_attachments_key() {
be_in_folder(folder);
// First, select the message with two attachments.
select_none();
select_click_row(3);
// Expand the attachment list.
mc.click(mc.eid("attachmentToggle"));
let attachmentList = mc.e("attachmentList");
mc.keypress(new elib.Elem(attachmentList), "a", {accelKey: true});
assert_equals(attachmentList.selectedItems.length, 2,
"Should have selected all attachments!");
}
function test_delete_attachment_key() {
be_in_folder(folder);
// First, select the message with two attachments.
select_none();
select_click_row(3);
// Expand the attachment list.
mc.click(mc.eid("attachmentToggle"));
let firstAttachment = new elib.Elem(mc.e("attachmentList").firstChild);
mc.click(firstAttachment, 5, 5);
// Try deleting with the delete key
plan_for_modal_dialog("commonDialog", function(cdc) {
cdc.window.document.documentElement.cancelDialog();
});
mc.keypress(firstAttachment, "VK_DELETE", {});
wait_for_modal_dialog("commonDialog");
// Try deleting with the shift-delete key combo.
plan_for_modal_dialog("commonDialog", function(cdc) {
cdc.window.document.documentElement.cancelDialog();
});
mc.keypress(firstAttachment, "VK_DELETE", {shiftKey: true});
wait_for_modal_dialog("commonDialog");
}
function test_attachments_compose_menu() {
be_in_folder(folder);
// First, select the message with two attachments.
select_none();
select_click_row(3);
let cwc = open_compose_with_forward();

Просмотреть файл

@ -122,16 +122,16 @@ function setupModule(module) {
*/
function check_attachment_size(controller, index, expectedSize) {
let bucket = controller.e('attachmentBucket');
let node = bucket.getElementsByTagName('listitem')[index];
let node = bucket.getElementsByTagName('attachmentitem')[index];
// First, let's check that the 'attachmentSize' attribute is correct
// First, let's check that the attachment size is correct
let size = node.attachment.size;
if (Math.abs(size - expectedSize) > epsilon)
throw new Error('Reported attachment size ('+size+') not within epsilon ' +
'of actual attachment size ('+expectedSize+')');
// Next, make sure that the formatted size in the label is correct
let formattedSize = /\((.*?)\)$/.exec(node.getAttribute('label'))[1];
let formattedSize = node.getAttribute('size');
let expectedFormattedSize = messenger.formatFileSize(size);
if (formattedSize != expectedFormattedSize)
throw new Error('Formatted attachment size ('+formattedSize+') does not ' +
@ -145,12 +145,12 @@ function check_attachment_size(controller, index, expectedSize) {
*/
function check_no_attachment_size(controller, index) {
let bucket = controller.e('attachmentBucket');
let node = bucket.getElementsByTagName('listitem')[index];
let node = bucket.getElementsByTagName('attachmentitem')[index];
if (node.attachment.size != -1)
throw new Error('attachment.size attribute should be -1!');
if (/\((.*?)\)$/.exec(node.getAttribute('label')))
if (node.getAttribute('size') != '')
throw new Error('Attachment size should not be displayed!');
}
@ -161,7 +161,7 @@ function check_no_attachment_size(controller, index) {
*/
function check_total_attachment_size(controller, count) {
let bucket = controller.e("attachmentBucket");
let nodes = bucket.getElementsByTagName("listitem");
let nodes = bucket.getElementsByTagName("attachmentitem");
let sizeNode = controller.e("attachmentBucketSize");
if (nodes.length != count)
@ -252,7 +252,7 @@ function test_rename_attachment() {
// Now, rename the attachment.
let bucket = cwc.e("attachmentBucket");
let node = bucket.getElementsByTagName("listitem")[0];
let node = bucket.getElementsByTagName("attachmentitem")[0];
cwc.click(new elib.Elem(node));
plan_for_modal_dialog("commonDialog", subtest_rename_attachment);
cwc.window.RenameSelectedAttachment();

Просмотреть файл

@ -268,7 +268,7 @@ function add_attachment(aComposeWindow, aUrl, aSize) {
*/
function delete_attachment(aComposeWindow, aIndex) {
let bucket = aComposeWindow.e('attachmentBucket');
let node = bucket.getElementsByTagName('listitem')[aIndex];
let node = bucket.getElementsByTagName('attachmentitem')[aIndex];
aComposeWindow.click(new elib.Elem(node));
aComposeWindow.window.RemoveSelectedAttachment();

Просмотреть файл

@ -19,6 +19,8 @@ classic.jar:
skin/classic/messenger/messageBody.css (mail/messageBody.css)
skin/classic/messenger/messageQuotes.css (mail/messageQuotes.css)
skin/classic/messenger/messenger.css (mail/messenger.css)
skin/classic/messenger/attachmentList.css (mail/attachmentList.css)
skin/classic/messenger/imageFilters.svg (mail/imageFilters.svg)
skin/classic/messenger/mailWindow1.css (mail/mailWindow1.css)
skin/classic/messenger/tagColors.css (mail/tagColors.css)
skin/classic/messenger/messageWindow.css (mail/messageWindow.css)

Просмотреть файл

@ -0,0 +1,87 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Thunderbird
*
* The Initial Developer of the Original Code is
* Mozilla Messaging
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jim Porter <squibblyflabbetydoo@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* styles for the attachment list */
.attachmentcell-icon {
padding: 1px;
}
.attachmentcell-name,
.attachmentcell-size {
padding-top: 1px;
}
.attachmentcell-size {
color: GrayText;
}
attachmentlist[orient="horizontal"] > attachmentitem {
pointer-events: none;
}
attachmentlist[orient="horizontal"] .attachmentcell-icon,
attachmentlist[orient="horizontal"] .attachmentcell-nameselection {
pointer-events: auto;
}
attachmentlist:focus > attachmentitem[selected="true"][current="true"] .attachmentcell-nameselection {
outline: 1px dotted #F3D982;
}
attachmentlist:focus > attachmentitem[current="true"] .attachmentcell-nameselection {
outline: 1px dotted;
outline-offset: -1px;
}
attachmentitem[selected="true"] .attachmentcell-nameselection {
background-color: -moz-CellHighlight;
color: -moz-CellHighlightText;
}
attachmentlist:focus > attachmentitem[selected="true"] .attachmentcell-nameselection {
background-color: Highlight;
color: HighlightText;
}
attachmentitem[selected="true"] .attachmentcell-icon {
filter: url("chrome://messenger/skin/imageFilters.svg#selected");
}
attachmentlist:focus > attachmentitem[selected="true"] .attachmentcell-icon {
filter: url("chrome://messenger/skin/imageFilters.svg#selected-focus");
}

Просмотреть файл

@ -0,0 +1,57 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Mozilla Thunderbird.
-
- The Initial Developer of the Original Code is
- Mozilla Messaging.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Jim Porter <squibblyflabbetydoo@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="selected-focus">
<feFlood flood-color="Highlight" flood-opacity="0.7" result="color"/>
<feComposite in="color" in2="SourceAlpha" operator="in" result="mask"/>
<feMerge>
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="mask"/>
</feMerge>
</filter>
<filter id="selected">
<feFlood flood-color="-moz-CellHighlight" flood-opacity="0.7" result="color"/>
<feComposite in="color" in2="SourceAlpha" operator="in" result="mask"/>
<feMerge>
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="mask"/>
</feMerge>
</filter>
</svg>

Просмотреть файл

@ -119,7 +119,7 @@
/* ::::: attachment view ::::: */
#attachmentList {
margin: 0px;
margin: 0;
background-color: -moz-Field;
color: -moz-FieldText;
}
@ -176,47 +176,10 @@
list-style-image: url("moz-icon://stock/gtk-save?size=menu");
}
/* XXX: Move all of the description attributes to the toolkit */
description[selectable="true"] {
margin: 1px 5px 4px;
}
descriptionitem {
border: 1px solid transparent;
margin: 1px;
}
description[selectable="true"]:focus > descriptionitem[current="true"] {
border: 1px dotted #F5DB95;
}
descriptionitem[selected="true"] {
background-color: -moz-Dialog;
color: -moz-DialogText;
}
description[selectable="true"]:focus > descriptionitem[selected="true"] {
background-color: Highlight;
color: HighlightText;
}
.attachmentBox {
width: 15em;
}
#attachmentList[largeView="true"] .attachmentBox {
-moz-box-orient: vertical;
}
#attachmentView {
border-top: 1px solid ThreeDShadow;
}
#attachmentListWrapper[attachmentOverflow="true"] {
overflow: auto;
}
/* ::::: msg header captions ::::: */
#msgHeaderView {

Просмотреть файл

@ -21,6 +21,7 @@ classic.jar:
skin/classic/messenger/messageHeader.css (mail/messageHeader.css)
skin/classic/messenger/messageWindow.css (mail/messageWindow.css)
skin/classic/messenger/messageBody.css (mail/messageBody.css)
skin/classic/messenger/attachmentList.css (mail/attachmentList.css)
skin/classic/messenger/msgSelectOffline.css (mail/msgSelectOffline.css)
skin/classic/messenger/mailWindow1.css (mail/mailWindow1.css)
skin/classic/messenger/searchBox.css (mail/searchBox.css)

Просмотреть файл

@ -0,0 +1,80 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Thunderbird
*
* The Initial Developer of the Original Code is
* Mozilla Messaging
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jim Porter <squibblyflabbetydoo@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* styles for the attachment list */
/* ::::: attachment list ::::: */
.attachmentcell-icon {
padding: 1px;
}
.attachmentcell-name,
.attachmentcell-size {
padding-top: 1px;
}
.attachmentcell-size {
color: GrayText;
}
attachmentlist:focus > attachmentitem[selected="true"][current="true"] {
outline: 1px dotted #F3D982;
}
attachmentlist:focus > attachmentitem[current="true"] {
outline: 1px dotted;
outline-offset: -1px;
}
attachmentitem[selected="true"] {
background-color: -moz-CellHighlight;
color: -moz-CellHighlightText;
}
attachmentlist:focus > attachmentitem[selected="true"] {
background-color: Highlight;
color: HighlightText;
}
attachmentitem[selected="true"] .attachmentcell-size {
color: -moz-CellHighlightText;
}
attachmentlist:focus >attachmentitem[selected="true"] .attachmentcell-size {
color: HighlightText;
}

Просмотреть файл

@ -145,6 +145,8 @@
#attachmentList {
margin: 0px;
background-color: -moz-Field;
color: -moz-FieldText;
}
#attachmentToggle {
@ -203,56 +205,8 @@
padding-bottom: 0px !important;
}
/* XXX: Move all of the description attributes to the toolkit */
description {
margin: 0;
}
descriptionitem {
padding: 0px;
margin: 1px;
text-decoration: underline;
color: blue;
border: none !important;
}
description[selectable="true"]:focus > descriptionitem[selected="true"][current="true"] {
border: 1px solid #B8B8B8;
background-color: #C8C8C8;
}
descriptionitem[selected="true"] {
border: 1px solid #B8B8B8;
background-color: #C8C8C8;
}
description[selectable="true"]:focus > descriptionitem[selected="true"] {
border: 1px solid #B8B8B8;
background-color: #C8C8C8;
}
.descriptioncell-icon {
}
.attachmentBox {
width: 15em;
}
#attachmentView[largeView="true"] .attachmentBox{
-moz-box-orient: vertical;
}
#attachmentView {
background-color: #E6E6E6;
border: 1px solid #C8C8C8;
border-radius: 7px;
margin: 4px;
padding: 4px;
}
#attachmentListWrapper[attachmentOverflow="true"] {
overflow: auto;
border-top: 1px solid ThreeDShadow;
}
#attachment-splitter {
@ -261,6 +215,48 @@ description[selectable="true"]:focus > descriptionitem[selected="true"] {
background-color: #E6E6E6;
}
/* ::::: attachment list ::::: */
.attachmentcell-icon {
padding: 1px;
}
.attachmentcell-name,
.attachmentcell-size {
padding-top: 1px;
}
.attachmentcell-size {
color: GrayText;
}
attachmentlist:focus > attachmentitem[selected="true"][current="true"] {
outline: 1px dotted #F3D982;
}
attachmentlist:focus > attachmentitem[current="true"] {
outline: 1px dotted;
outline-offset: -1px;
}
attachmentitem[selected="true"] {
background-color: -moz-CellHighlight;
color: -moz-CellHighlightText;
}
attachmentlist:focus > attachmentitem[selected="true"] {
background-color: Highlight;
color: HighlightText;
}
attachmentitem[selected="true"] .attachmentcell-size {
color: -moz-CellHighlightText;
}
attachmentlist:focus >attachmentitem[selected="true"] .attachmentcell-size {
color: HighlightText;
}
/* ::::: msg header captions ::::: */
#msgHeaderView {

Просмотреть файл

@ -59,6 +59,8 @@ classic.jar:
skin/classic/messenger/messageBody.css (mail/messageBody.css)
skin/classic/messenger/messageQuotes.css (mail/messageQuotes.css)
skin/classic/messenger/messenger.css (mail/messenger.css)
skin/classic/messenger/attachmentList.css (mail/attachmentList.css)
skin/classic/messenger/imageFilters.svg (mail/imageFilters.svg)
skin/classic/messenger/mailWindow1.css (mail/mailWindow1.css)
skin/classic/messenger/tagColors.css (mail/tagColors.css)
skin/classic/messenger/messageWindow.css (mail/messageWindow.css)
@ -293,6 +295,8 @@ classic.jar:
skin/classic/aero/messenger/messageBody.css (mail/messageBody.css)
skin/classic/aero/messenger/messageQuotes.css (mail/messageQuotes.css)
* skin/classic/aero/messenger/messenger.css (mail/messenger-aero.css)
skin/classic/aero/messenger/attachmentList.css (mail/attachmentList.css)
skin/classic/aero/messenger/imageFilters.svg (mail/imageFilters.svg)
* skin/classic/aero/messenger/mailWindow1.css (mail/mailWindow1-aero.css)
skin/classic/aero/messenger/tagColors.css (mail/tagColors.css)
skin/classic/aero/messenger/messageWindow.css (mail/messageWindow.css)

Просмотреть файл

@ -0,0 +1,87 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Thunderbird
*
* The Initial Developer of the Original Code is
* Mozilla Messaging
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jim Porter <squibblyflabbetydoo@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* styles for the attachment list */
.attachmentcell-icon {
padding: 1px;
}
.attachmentcell-name,
.attachmentcell-size {
padding-top: 1px;
}
.attachmentcell-size {
color: GrayText;
}
attachmentlist[orient="horizontal"] > attachmentitem {
pointer-events: none;
}
attachmentlist[orient="horizontal"] .attachmentcell-icon,
attachmentlist[orient="horizontal"] .attachmentcell-nameselection {
pointer-events: auto;
}
attachmentlist:focus > attachmentitem[selected="true"][current="true"] .attachmentcell-nameselection {
outline: 1px dotted #F3D982;
}
attachmentlist:focus > attachmentitem[current="true"] .attachmentcell-nameselection {
outline: 1px dotted;
outline-offset: -1px;
}
attachmentitem[selected="true"] .attachmentcell-nameselection {
background-color: -moz-CellHighlight;
color: -moz-CellHighlightText;
}
attachmentlist:focus > attachmentitem[selected="true"] .attachmentcell-nameselection {
background-color: Highlight;
color: HighlightText;
}
attachmentitem[selected="true"] .attachmentcell-icon {
filter: url("chrome://messenger/skin/imageFilters.svg#selected");
}
attachmentlist:focus > attachmentitem[selected="true"] .attachmentcell-icon {
filter: url("chrome://messenger/skin/imageFilters.svg#selected-focus");
}

Просмотреть файл

@ -0,0 +1,57 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Mozilla Thunderbird.
-
- The Initial Developer of the Original Code is
- Mozilla Messaging.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Jim Porter <squibblyflabbetydoo@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="selected-focus">
<feFlood flood-color="Highlight" flood-opacity="0.7" result="color"/>
<feComposite in="color" in2="SourceAlpha" operator="in" result="mask"/>
<feMerge>
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="mask"/>
</feMerge>
</filter>
<filter id="selected">
<feFlood flood-color="-moz-CellHighlight" flood-opacity="0.7" result="color"/>
<feComposite in="color" in2="SourceAlpha" operator="in" result="mask"/>
<feMerge>
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="mask"/>
</feMerge>
</filter>
</svg>

Просмотреть файл

@ -211,47 +211,10 @@
list-style-image: url("chrome://messenger/skin/icons/download.png");
}
/* XXX: Move all of the description attributes to the toolkit */
description[selectable="true"] {
margin: 1px 5px 4px;
}
descriptionitem {
border: 1px solid transparent;
margin: 1px;
}
description[selectable="true"]:focus > descriptionitem[current="true"] {
border: 1px dotted #F5DB95;
}
descriptionitem[selected="true"] {
background-color: -moz-Dialog;
color: -moz-DialogText;
}
description[selectable="true"]:focus > descriptionitem[selected="true"] {
background-color: Highlight;
color: HighlightText;
}
.attachmentBox {
width: 15em;
}
#attachmentView[largeView="true"] .attachmentBox {
-moz-box-orient: vertical;
}
#attachmentView {
border-top: 1px solid ThreeDShadow;
}
#attachmentListWrapper[attachmentOverflow="true"] {
overflow: auto;
}
/* ::::: msg header captions ::::: */
#msgHeaderView {

Просмотреть файл

@ -193,47 +193,10 @@
-moz-image-region: rect(0px 192px 16px 176px);
}
/* XXX: Move all of the description attributes to the toolkit */
description[selectable="true"] {
margin: 1px 5px 4px;
}
descriptionitem {
border: 1px solid transparent;
margin: 1px;
}
description[selectable="true"]:focus > descriptionitem[current="true"] {
border: 1px dotted #F5DB95;
}
descriptionitem[selected="true"] {
background-color: -moz-Dialog;
color: -moz-DialogText;
}
description[selectable="true"]:focus > descriptionitem[selected="true"] {
background-color: Highlight;
color: HighlightText;
}
.attachmentBox {
width: 15em;
}
#attachmentView[largeView="true"] .attachmentBox {
-moz-box-orient: vertical;
}
#attachmentView {
border-top: 1px solid ThreeDShadow;
}
#attachmentListWrapper[attachmentOverflow="true"] {
overflow: auto;
}
/* ::::: msg header captions ::::: */
#msgHeaderView {