зеркало из https://github.com/mozilla/snowl.git
some more headers tweakage, handle all sorts of wrap/flow cases, add global wrap option, make height persistence better.
This commit is contained in:
Родитель
15f5061a60
Коммит
b090bad5db
|
@ -295,6 +295,27 @@ let Snowl = {
|
|||
}
|
||||
},
|
||||
|
||||
onSetHeaderWrap: function(aEvent) {
|
||||
let contentDoc = gBrowser.selectedBrowser.contentDocument;
|
||||
let messageHeader = contentDoc.getElementById("messageHeader");
|
||||
let viewHdrChecked = document.getElementById("viewSnowlHeader").
|
||||
getAttribute("checked") == "true";
|
||||
let body = messageHeader.contentDocument.getElementById("body");
|
||||
let headerDeck = messageHeader.contentDocument.getElementById("headerDeck");
|
||||
|
||||
// If a snowl message is in the tab, showing header, resize for wrapped flow.
|
||||
if (messageHeader) {
|
||||
if (aEvent.target.getAttribute("checked") == "true")
|
||||
body.classList.add("wrap");
|
||||
else
|
||||
body.classList.remove("wrap");
|
||||
}
|
||||
|
||||
if (viewHdrChecked)
|
||||
messageHeader.contentWindow.wrappedJSObject.
|
||||
messageHeaderUtils.setHeaderSize(body, headerDeck);
|
||||
},
|
||||
|
||||
_toggleToolbar: function(event) {
|
||||
let doc = document.getElementById("sidebar").contentDocument;
|
||||
let toolbar = doc.getElementById("snowlToolbar");
|
||||
|
|
|
@ -155,6 +155,14 @@
|
|||
<menuitem observes="viewSnowlHeader"
|
||||
label="&showHeader.label;"
|
||||
accesskey="&showHeader.accesskey;"/>
|
||||
<menuitem id="viewSnowlHeaderWrap"
|
||||
label="&wrapHeader.label;"
|
||||
autoCheck="false"
|
||||
type="checkbox"
|
||||
accesskey="&wrapHeader.accesskey;"
|
||||
checked="false"
|
||||
persist="checked"
|
||||
oncommand="Snowl.onSetHeaderWrap(event)"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="snowlToolbarMenuitem"
|
||||
label="&toolbar.label;"
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
#messageFrame[header="brief"] > #messageHeader,
|
||||
#messageFrame[header="basic"] > #messageHeader {
|
||||
overflow-x: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Set visibility when header collapsed to prevent tab stops */
|
||||
|
@ -75,23 +75,10 @@ table {
|
|||
#noHeader[collapsed="true"],
|
||||
#headerDeck:not([header="brief"]) .briefHeader,
|
||||
#headerDeck[header="brief"] .basicHeaderRow,
|
||||
#headerDeck[header="brief"] + #headerFull,
|
||||
#headerDeck[header="basic"] + #headerFull {
|
||||
#headerDeck[header="brief"] + #headerFullTable,
|
||||
#headerDeck[header="basic"] + #headerFullTable {
|
||||
display: none;
|
||||
}
|
||||
/*
|
||||
tr {
|
||||
border: 1px solid black;
|
||||
}
|
||||
td {
|
||||
border: 1px solid red;
|
||||
}
|
||||
div, p, a, pre {
|
||||
border: 1px solid blue;
|
||||
}
|
||||
table {
|
||||
border: 3px solid green;
|
||||
}*/
|
||||
|
||||
.headerButtons {
|
||||
white-space: nowrap;
|
||||
|
@ -110,16 +97,19 @@ table {
|
|||
width: 1%;
|
||||
}
|
||||
|
||||
.headerLabel:hover {
|
||||
.headerLabel.wrapped:hover,
|
||||
.headerLabel.wrappable:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.headerLabel.wrap {
|
||||
border-right: 1px solid black;
|
||||
body.wrap > table > tr > .headerLabel:hover {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
body.wrap > table > tr > .headerLabel + .headerData > a,
|
||||
.headerLabel.wrap + .headerData > a {
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.headerData {
|
||||
|
@ -134,6 +124,8 @@ table {
|
|||
width: 35%;
|
||||
}
|
||||
|
||||
/* The date is difficult to style, as it must stick to the right edge, which
|
||||
* doesn't seem to allow for optimal wrapping and flexing and min widths. */
|
||||
#briefHeaderRow > .headerDataLast {
|
||||
padding-right: 4px;
|
||||
width: 5%;
|
||||
|
@ -141,24 +133,32 @@ table {
|
|||
}
|
||||
|
||||
#briefHeaderRow > .flexer {
|
||||
width: 2%;
|
||||
width: 1%;
|
||||
}
|
||||
|
||||
.fullHeaderRow > .headerData {
|
||||
overflow-x: auto;
|
||||
.headerPadTop,
|
||||
.headerPadBottom{
|
||||
height: .5em;
|
||||
}
|
||||
|
||||
#headerDeck:not([header="brief"]) > #briefHeaderRow > .headerDataSubject,
|
||||
#headerDeck:not([header="brief"]) > #briefHeaderRow > .headerLabelSubject {
|
||||
padding-top: .5em;
|
||||
#headerDeck:not([header="brief"]) > tr > .headerPadBottom {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#headerDeck[deleted] > #briefHeaderRow > .headerDataSubject > #subject{
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.fullHeaderRow > .headerData {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#headerFullTable > tr:nth-child(even) {
|
||||
background: darkgray;
|
||||
}
|
||||
|
||||
.fullHeaderRowSeparator {
|
||||
border-bottom: 1px solid threedshadow;
|
||||
border-top: 1px solid threedshadow;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,10 +64,12 @@
|
|||
dir="&locale.dir;"
|
||||
onload="messageContent.createHeader();"
|
||||
onclick="messageHeaderUtils.onClick(event);"
|
||||
onresize="messageHeaderUtils.onResize();"
|
||||
onmousemove="messageHeaderUtils.onMouseMove(event);"
|
||||
onpageshow="messageHeaderUtils.init();">
|
||||
<table id="headerDeck">
|
||||
<tr id="briefHeaderRow">
|
||||
<td class="headerButtons" valign="top" rowspan="2">
|
||||
<tr id="briefHeaderButtons">
|
||||
<td class="headerButtons" valign="top" rowspan="5">
|
||||
<xul:toolbarbutton id="pinButton"
|
||||
class="toolbarbutton-1"
|
||||
type="checkbox"
|
||||
|
@ -80,17 +82,33 @@
|
|||
<xul:toolbarbutton id="headerButton"
|
||||
class="toolbarbutton-1 tabbable"
|
||||
header="full"
|
||||
oncommand="messageHeaderUtils.toggleHeader(null, 'toggle');"
|
||||
oncommand="messageHeaderUtils.toggleHeader(null, null, 'toggle');"
|
||||
onmouseover="messageHeaderUtils.tooltip(event, 'show');"
|
||||
onmousedown="messageHeaderUtils.tooltip(event, 'hide');"
|
||||
onmouseout="messageHeaderUtils.tooltip(event, 'hide');"
|
||||
onkeypress="messageHeaderUtils.onButtonKeyPress(event);"
|
||||
tooltiptext="&toggleHeader.tooltip;"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="headerPadTop" colspan="2"/>
|
||||
<td class="headerButtons basicHeaderRow" valign="top" rowspan="5">
|
||||
<xul:toolbarbutton id="deleteMessageButton"
|
||||
class="toolbarbutton-1 tabbable"
|
||||
oncommand="messageHeaderUtils.onDeleteMessageButton()"
|
||||
onmouseover="messageHeaderUtils.tooltip(event, 'show');"
|
||||
onmousedown="messageHeaderUtils.tooltip(event, 'hide');"
|
||||
onmouseout="messageHeaderUtils.tooltip(event, 'hide');"
|
||||
tooltiptext="&deleteMessagesButton.tooltip;"/>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr id="briefHeaderRow">
|
||||
<!-- Do not leave any space/comments or wrap/indent between headerLabel
|
||||
and headerData </td><td elements as this will create a #text node and
|
||||
disrupt nextSibling usage. -->
|
||||
<td class="headerLabel headerLabelSubject" align="right">&subject.label;</td><td
|
||||
<td class="headerLabel headerLabelSubject altrowA" align="right">&subject.label;</td><td
|
||||
class="headerData headerDataSubject"><a id="subject"/></td>
|
||||
<td class="briefHeader flexer"/>
|
||||
|
||||
|
@ -105,35 +123,29 @@
|
|||
|
||||
<td class="headerLabel briefHeader">×tamp.label;</td><td
|
||||
class="headerData briefHeader headerDataLast"><a id="briefTimestamp"/></td>
|
||||
|
||||
<td class="headerButtons basicHeaderRow" valign="top" rowspan="2">
|
||||
<xul:toolbarbutton id="deleteMessageButton"
|
||||
class="toolbarbutton-1 tabbable"
|
||||
oncommand="messageHeaderUtils.onDeleteMessageButton()"
|
||||
onmouseover="messageHeaderUtils.tooltip(event, 'show');"
|
||||
onmousedown="messageHeaderUtils.tooltip(event, 'hide');"
|
||||
onmouseout="messageHeaderUtils.tooltip(event, 'hide');"
|
||||
tooltiptext="&deleteMessagesButton.tooltip;"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr><td class="headerPadBottom" colspan="2"/></tr>
|
||||
|
||||
|
||||
<tr class="basicHeaderRow">
|
||||
<td class="headerLabel">&author.label;</td><td
|
||||
<td class="headerLabel altrowB">&author.label;</td><td
|
||||
class="headerData"><a id="author"/></td>
|
||||
</tr>
|
||||
|
||||
<tr class="basicHeaderRow">
|
||||
<td class="headerLabel" colspan="2">×tamp.label;</td><td
|
||||
class="headerData"><a id="timestamp" colspan="2"/></td>
|
||||
<td class="headerLabel altrowA" colspan="2">×tamp.label;</td><td
|
||||
class="headerData"><a id="timestamp" colspan="3"/></td>
|
||||
</tr>
|
||||
<!-- -->
|
||||
</table>
|
||||
<div id="headerFull">
|
||||
<table id="headerFullTable" class="fullHeaderTable">
|
||||
<tr class="fullHeaderRow">
|
||||
<td class="fullHeaderRowSeparator" colspan="3"/>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Full headers table rows are dynamically created. -->
|
||||
<table id="headerFullTable" class="fullHeaderTable">
|
||||
<tr class="fullHeaderRow">
|
||||
<td class="fullHeaderRowSeparator" colspan="3"/>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -246,11 +246,17 @@ var messageContent = {
|
|||
|
||||
var messageHeaderUtils = {
|
||||
ROWS_BRIEF: "30,*",
|
||||
origWidth: null,
|
||||
origHeight: null,
|
||||
noResize: false,
|
||||
|
||||
init: function() {
|
||||
var pin = document.getElementById("pinButton");
|
||||
var headerBcaster = gBrowserWindow.document.
|
||||
getElementById("viewSnowlHeader");
|
||||
var wrap = gBrowserWindow.document.
|
||||
getElementById("viewSnowlHeaderWrap");
|
||||
var body = document.getElementById("body");
|
||||
var headerDeck = document.getElementById("headerDeck");
|
||||
var noHeader = parent.document.
|
||||
documentElement.getElementsByClassName("noHeader")[0];
|
||||
|
@ -263,7 +269,7 @@ var messageHeaderUtils = {
|
|||
if (checked) {
|
||||
// Collapse hover area, set header.
|
||||
noHeader.setAttribute("collapsed", true);
|
||||
this.toggleHeader(headerDeck, "init");
|
||||
this.toggleHeader(body, headerDeck, "init");
|
||||
}
|
||||
else {
|
||||
// Uncollapse hover area, hide header frame.
|
||||
|
@ -271,23 +277,62 @@ var messageHeaderUtils = {
|
|||
parent.document.body.rows = "0,*";
|
||||
noHeader.removeAttribute("collapsed");
|
||||
}
|
||||
|
||||
if (wrap.getAttribute("checked") == "true")
|
||||
body.classList.add("wrap");
|
||||
else
|
||||
body.classList.remove("wrap");
|
||||
|
||||
// Fires after onresize done, store new width and height.
|
||||
window.addEventListener("MozScrolledAreaChanged",
|
||||
function () {
|
||||
messageHeaderUtils.origWidth =
|
||||
parent.document.body.
|
||||
clientWidth;
|
||||
messageHeaderUtils.origHeight =
|
||||
parent.document.getElementById("messageHeader").
|
||||
clientHeight; },
|
||||
false);
|
||||
},
|
||||
|
||||
onMouseOver: function(aEvent) {
|
||||
var node = aEvent.target;
|
||||
var messageHeader = document.getElementById("messageHeader");
|
||||
var body = messageHeader.contentDocument.getElementById("body");
|
||||
var headerDeck = messageHeader.contentDocument.getElementById("headerDeck");
|
||||
var pin = messageHeader.contentDocument.getElementById("pinButton");
|
||||
if (node.id != "noHeader" || pin.hasAttribute("checked"))
|
||||
return;
|
||||
|
||||
this.headertimer = window.setTimeout(function() {
|
||||
messageHeaderUtils.toggleHeader(headerDeck);
|
||||
messageHeaderUtils.toggleHeader(body, headerDeck, "hover");
|
||||
document.getElementById("noHeader").
|
||||
setAttribute("collapsed", true);
|
||||
}, 500);
|
||||
},
|
||||
|
||||
onMouseMove: function(aEvent) {
|
||||
var node = aEvent.target;
|
||||
if (node.classList.contains("headerLabel")) {
|
||||
// Hovering a header label. Set cursor to indicate toggle for wrap mode
|
||||
// based on wrap state and wrappability.
|
||||
if (node.nextSibling.clientWidth < node.nextSibling.firstChild.offsetWidth)
|
||||
node.classList.add("wrappable");
|
||||
else
|
||||
node.classList.remove("wrappable");
|
||||
|
||||
var dataCStyle = window.getComputedStyle(node, null)
|
||||
// Need the height of the <a> content as the containing <td> sizes to match
|
||||
// any other <td> in the row that has expanded to fit wrapped content.
|
||||
var dataHt = node.nextSibling.firstChild.scrollHeight;
|
||||
var dataLnHt = dataCStyle.getPropertyValue("line-height").replace(/px/, "");
|
||||
if (dataHt != dataLnHt)
|
||||
node.classList.add("wrapped");
|
||||
else
|
||||
node.classList.remove("wrapped");
|
||||
}
|
||||
},
|
||||
|
||||
onMouseOut: function(aEvent) {
|
||||
window.clearTimeout(this.headertimer);
|
||||
delete this.headertimer;
|
||||
|
@ -297,6 +342,9 @@ var messageHeaderUtils = {
|
|||
if (node.id != "messageHeader" || pin.hasAttribute("checked"))
|
||||
return;
|
||||
|
||||
// Set noResize in scope of messageHeader frame document, which listens for
|
||||
// the onResize event.
|
||||
messageHeader.contentWindow.wrappedJSObject.messageHeaderUtils.noResize = true;
|
||||
document.getElementById("messageFrame").setAttribute("border", "0");
|
||||
document.getElementById("messageFrame").setAttribute("rows", "0,*");
|
||||
document.getElementById("noHeader").removeAttribute("collapsed");
|
||||
|
@ -320,25 +368,54 @@ var messageHeaderUtils = {
|
|||
headerBcaster.setAttribute("checked", pin.checked);
|
||||
},
|
||||
|
||||
toggleHeader: function(headerDeck, aType) {
|
||||
setHeaderSize: function(aBody, aHeaderDeck) {
|
||||
// Calculate how to set header height, given wrap toggling and splitter dnd.
|
||||
var headerBcaster = gBrowserWindow.document.getElementById("viewSnowlHeader");
|
||||
var headerIndex = parseInt(headerBcaster.getAttribute("headerIndex"));
|
||||
var rowsBasic = headerBcaster.getAttribute("rowsBasic");
|
||||
var rowsFull = headerBcaster.getAttribute("rowsFull");
|
||||
if ((this.isWrapped(aHeaderDeck) || aBody.classList.contains("wrap")) &&
|
||||
headerIndex != 2)
|
||||
// Reset header frame height to flow wrapped content. Full header scrolls,
|
||||
// so not necessary for 2.
|
||||
parent.document.body.rows = aBody.scrollHeight + ",*";
|
||||
else
|
||||
// Restore user set height if nothing wraps, or on init and mouseover/out.
|
||||
parent.document.body.rows = headerIndex == 0 ? this.ROWS_BRIEF :
|
||||
headerIndex == 1 ? rowsBasic : rowsFull;
|
||||
|
||||
if (aType != "init" && headerBcaster.getAttribute("checked") == "true") {
|
||||
// To set a header height: must first be in non Brief header, pin must be
|
||||
// checked, height can be dnd adjusted as desired, then header must be
|
||||
// toggled to save the height.
|
||||
if (headerIndex == 1)
|
||||
headerBcaster.setAttribute("rowsBasic", parent.document.body.rows);
|
||||
if (headerIndex == 2)
|
||||
headerBcaster.setAttribute("rowsFull", parent.document.body.rows);
|
||||
this.noResize = true;
|
||||
},
|
||||
|
||||
isWrapped: function(aHeaderDeck) {
|
||||
// Is any row in the brief/basic headers wrapped? Not just toggled to wrap,
|
||||
// but also flowed to multiple lines.
|
||||
var oneWrapped = false;
|
||||
var headerDeck = aHeaderDeck;
|
||||
|
||||
var wrappedNodes = headerDeck.getElementsByClassName("wrap");
|
||||
for (var i = 0; i < wrappedNodes.length && !oneWrapped; i++) {
|
||||
var node = wrappedNodes[i];
|
||||
var dataCStyle = window.getComputedStyle(node, null)
|
||||
var dataHt = dataCStyle.getPropertyValue("height");
|
||||
var dataLnHt = dataCStyle.getPropertyValue("line-height");
|
||||
if (dataHt != dataLnHt)
|
||||
oneWrapped = true;
|
||||
}
|
||||
|
||||
return oneWrapped;
|
||||
},
|
||||
|
||||
toggleHeader: function(aBody, aHeaderDeck, aType) {
|
||||
var headerBcaster = gBrowserWindow.document.getElementById("viewSnowlHeader");
|
||||
var headerIndex = parseInt(headerBcaster.getAttribute("headerIndex"));
|
||||
var body = aBody ? aBody :
|
||||
document.getElementById("body");
|
||||
var headerDeck = aHeaderDeck ? aHeaderDeck :
|
||||
document.getElementById("headerDeck");
|
||||
|
||||
if (aType == "toggle") {
|
||||
// Toggled to next in 3 way
|
||||
headerDeck = document.getElementById("headerDeck");
|
||||
headerIndex = ++headerIndex > 2 ? 0 : headerIndex++;
|
||||
headerBcaster.setAttribute("headerIndex", headerIndex);
|
||||
}
|
||||
|
@ -348,13 +425,15 @@ var messageHeaderUtils = {
|
|||
headerDeck.setAttribute("header", headerType);
|
||||
parent.document.body.setAttribute("header", headerType);
|
||||
parent.document.body.setAttribute("border", "6");
|
||||
parent.document.body.rows = headerIndex == 0 ? this.ROWS_BRIEF :
|
||||
headerIndex == 1 ? rowsBasic : rowsFull;
|
||||
|
||||
// The message is found in the scope of the parent frameset document.
|
||||
var messageContent = parent.wrappedJSObject.messageContent;
|
||||
if (headerIndex == 2 && !messageContent._headers)
|
||||
messageContent.createFullHeader(headerDeck);
|
||||
|
||||
// Set the size to persisted values or make sure toggling results in nice
|
||||
// headers wrapped content flow.
|
||||
this.setHeaderSize(body, headerDeck);
|
||||
},
|
||||
|
||||
onDeleteMessageButton: function() {
|
||||
|
@ -364,8 +443,61 @@ var messageHeaderUtils = {
|
|||
},
|
||||
|
||||
onClick: function(aEvent) {
|
||||
if (aEvent.target.classList.contains("headerLabel") && aEvent.button == 0)
|
||||
aEvent.target.classList.toggle("wrap");
|
||||
if (aEvent.button != 0)
|
||||
return;
|
||||
|
||||
var node = aEvent.target;
|
||||
if (node.classList.contains("headerLabel")) {
|
||||
// Clicked on a header label.
|
||||
var body = document.getElementById("body");
|
||||
var headerDeck = document.getElementById("headerDeck");
|
||||
if (!body.classList.contains("wrap")) {
|
||||
// Set wrap and resize only if global wrap not set.
|
||||
node.classList.toggle("wrap");
|
||||
this.setHeaderSize(body, headerDeck);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onResize: function() {
|
||||
var messageHeader = parent.document.getElementById("messageHeader");
|
||||
var body = document.getElementById("body");
|
||||
var headerDeck = document.getElementById("headerDeck");
|
||||
var headerBcaster = gBrowserWindow.document.getElementById("viewSnowlHeader");
|
||||
var headerIndex = parseInt(headerBcaster.getAttribute("headerIndex"));
|
||||
var rowsBasic = headerBcaster.getAttribute("rowsBasic");
|
||||
var rowsFull = headerBcaster.getAttribute("rowsFull");
|
||||
var newWidth = parent.document.body.clientWidth;
|
||||
var newHeight = messageHeader.clientHeight;
|
||||
|
||||
if (this.origWidth != newWidth && headerIndex != 2) {
|
||||
// If the sidebar width has changed, make sure things reflow nicely; since
|
||||
// the full header has a scrollbar, only necessary for brief/basic headers.
|
||||
if (this.isWrapped(headerDeck) || body.classList.contains("wrap"))
|
||||
// Reset header frame height to flow wrapped content.
|
||||
parent.document.body.rows = body.scrollHeight + ",*";
|
||||
else
|
||||
// Restore user set height if nothing wraps.
|
||||
parent.document.body.rows = headerIndex == 0 ? this.ROWS_BRIEF :
|
||||
headerIndex == 1 ? rowsBasic : rowsFull;
|
||||
}
|
||||
|
||||
if (this.noResize) {
|
||||
// Do not resize if size changed due to header label click, or
|
||||
// mouseover/out header show/hide. All height resizes must come from
|
||||
// dragging the frame border, for persisting height.
|
||||
this.noResize = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.origHeight != newHeight && this.origWidth == newWidth) {
|
||||
// Just height changed, must be only due to dnd resize, persist new height.
|
||||
// There is no frames event that would make persisting height more direct.
|
||||
if (headerIndex == 1)
|
||||
headerBcaster.setAttribute("rowsBasic", parent.document.body.rows);
|
||||
if (headerIndex == 2)
|
||||
headerBcaster.setAttribute("rowsFull", parent.document.body.rows);
|
||||
}
|
||||
},
|
||||
|
||||
tooltip: function(aEvent, aShow) {
|
||||
|
|
|
@ -61,6 +61,8 @@
|
|||
|
||||
<!ENTITY showHeader.label "Show Header">
|
||||
<!ENTITY showHeader.accesskey "H">
|
||||
<!ENTITY wrapHeader.label "Wrap All Headers">
|
||||
<!ENTITY wrapHeader.accesskey "W">
|
||||
<!ENTITY toolbar.label "Sidebar Toolbar">
|
||||
<!ENTITY toolbar.accesskey "d">
|
||||
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
<!ENTITY pinButton.label "Pin Header">
|
||||
<!ENTITY pinButton.tooltip "Toggle pin to set and unset permanent header">
|
||||
<!ENTITY toggleHeader.label "Toggle Header">
|
||||
<!ENTITY toggleHeader.tooltip "Toggle message header to brief, basic, or full; in basic or full header, toggle to save height after adjustment">
|
||||
<!ENTITY toggleHeader.tooltip "Toggle message header to brief, basic, or full">
|
||||
<!ENTITY deleteMessagesButton.label "Delete Message">
|
||||
<!ENTITY deleteMessagesButton.tooltip "Delete this Message">
|
||||
|
|
Загрузка…
Ссылка в новой задаче