summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/im/content/imStatusSelector.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/im/content/imStatusSelector.js')
-rw-r--r--comm/mail/components/im/content/imStatusSelector.js383
1 files changed, 383 insertions, 0 deletions
diff --git a/comm/mail/components/im/content/imStatusSelector.js b/comm/mail/components/im/content/imStatusSelector.js
new file mode 100644
index 0000000000..69bbc2776a
--- /dev/null
+++ b/comm/mail/components/im/content/imStatusSelector.js
@@ -0,0 +1,383 @@
+/* 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/. */
+
+var { Status } = ChromeUtils.importESModule(
+ "resource:///modules/imStatusUtils.sys.mjs"
+);
+var { IMServices } = ChromeUtils.importESModule(
+ "resource:///modules/IMServices.sys.mjs"
+);
+var { ChatIcons } = ChromeUtils.importESModule(
+ "resource:///modules/chatIcons.sys.mjs"
+);
+
+var statusSelector = {
+ observe(aSubject, aTopic, aMsg) {
+ if (aTopic == "status-changed") {
+ this.displayCurrentStatus();
+ } else if (aTopic == "user-icon-changed") {
+ this.displayUserIcon();
+ } else if (aTopic == "user-display-name-changed") {
+ this.displayUserDisplayName();
+ }
+ },
+
+ displayUserIcon() {
+ let icon = IMServices.core.globalUserStatus.getUserIcon();
+ ChatIcons.setUserIconSrc(
+ document.getElementById("userIcon"),
+ icon?.spec,
+ true
+ );
+ },
+
+ displayUserDisplayName() {
+ let displayName = IMServices.core.globalUserStatus.displayName;
+ let elt = document.getElementById("displayName");
+ if (displayName) {
+ elt.removeAttribute("usingDefault");
+ } else {
+ let bundle = Services.strings.createBundle(
+ "chrome://messenger/locale/chat.properties"
+ );
+ displayName = bundle.GetStringFromName("displayNameEmptyText");
+ elt.setAttribute("usingDefault", displayName);
+ }
+ elt.setAttribute("value", displayName);
+ },
+
+ displayStatusType(aStatusType) {
+ document
+ .getElementById("statusMessageLabel")
+ .setAttribute("statusType", aStatusType);
+ let statusString = Status.toLabel(aStatusType);
+ let statusTypeIcon = document.getElementById("statusTypeIcon");
+ statusTypeIcon.setAttribute("status", aStatusType);
+ statusTypeIcon.setAttribute("tooltiptext", statusString);
+ return statusString;
+ },
+
+ displayCurrentStatus() {
+ let us = IMServices.core.globalUserStatus;
+ let status = Status.toAttribute(us.statusType);
+ let message = status == "offline" ? "" : us.statusText;
+ let statusMessage = document.getElementById("statusMessageLabel");
+ if (!statusMessage) {
+ // Chat toolbar not in the DOM yet
+ return;
+ }
+ if (message) {
+ statusMessage.removeAttribute("usingDefault");
+ } else {
+ let statusString = this.displayStatusType(status);
+ statusMessage.setAttribute("usingDefault", statusString);
+ message = statusString;
+ }
+ statusMessage.setAttribute("value", message);
+ statusMessage.setAttribute("tooltiptext", message);
+ },
+
+ editStatus(aEvent) {
+ let status = aEvent.target.getAttribute("status");
+ if (status == "offline") {
+ IMServices.core.globalUserStatus.setStatus(
+ Ci.imIStatusInfo.STATUS_OFFLINE,
+ ""
+ );
+ } else if (status) {
+ this.startEditStatus(status);
+ }
+ },
+
+ startEditStatus(aStatusType) {
+ let currentStatusType = document
+ .getElementById("statusTypeIcon")
+ .getAttribute("status");
+ if (aStatusType != currentStatusType) {
+ this._statusTypeBeforeEditing = currentStatusType;
+ this._statusTypeEditing = aStatusType;
+ this.displayStatusType(aStatusType);
+ }
+ this.statusMessageClick();
+ },
+
+ statusMessageClick() {
+ let statusMessage = document.getElementById("statusMessageLabel");
+ let statusMessageInput = document.getElementById("statusMessageInput");
+ statusMessage.setAttribute("hidden", "true");
+ statusMessageInput.removeAttribute("hidden");
+ let statusType = document
+ .getElementById("statusTypeIcon")
+ .getAttribute("status");
+ if (statusType == "offline" || statusMessage.disabled) {
+ return;
+ }
+
+ if (!statusMessageInput.hasAttribute("editing")) {
+ statusMessageInput.setAttribute("editing", "true");
+ statusMessageInput.addEventListener("blur", event => {
+ this.finishEditStatusMessage(true);
+ });
+ if (statusMessage.hasAttribute("usingDefault")) {
+ if (
+ "_statusTypeBeforeEditing" in this &&
+ this._statusTypeBeforeEditing == "offline"
+ ) {
+ statusMessageInput.setAttribute(
+ "value",
+ IMServices.core.globalUserStatus.statusText
+ );
+ } else {
+ statusMessageInput.removeAttribute("value");
+ }
+ } else {
+ statusMessageInput.setAttribute(
+ "value",
+ statusMessage.getAttribute("value")
+ );
+ }
+
+ if (Services.prefs.getBoolPref("mail.spellcheck.inline")) {
+ statusMessageInput.setAttribute("spellcheck", "true");
+ } else {
+ statusMessageInput.removeAttribute("spellcheck");
+ }
+
+ // force binding attachment by forcing layout
+ statusMessageInput.getBoundingClientRect();
+ statusMessageInput.select();
+ }
+
+ this.statusMessageRefreshTimer();
+ },
+
+ statusMessageRefreshTimer() {
+ const timeBeforeAutoValidate = 20 * 1000;
+ if ("_stopEditStatusTimeout" in this) {
+ clearTimeout(this._stopEditStatusTimeout);
+ }
+ this._stopEditStatusTimeout = setTimeout(
+ this.finishEditStatusMessage,
+ timeBeforeAutoValidate,
+ true
+ );
+ },
+
+ statusMessageKeyPress(aEvent) {
+ if (!this.hasAttribute("editing")) {
+ if (aEvent.keyCode == aEvent.DOM_VK_DOWN) {
+ let button = document.getElementById("statusTypeIcon");
+ document.getElementById("setStatusTypeMenupopup").openPopup(button);
+ }
+ return;
+ }
+
+ switch (aEvent.keyCode) {
+ case aEvent.DOM_VK_RETURN:
+ statusSelector.finishEditStatusMessage(true);
+ break;
+
+ case aEvent.DOM_VK_ESCAPE:
+ statusSelector.finishEditStatusMessage(false);
+ break;
+
+ default:
+ statusSelector.statusMessageRefreshTimer();
+ }
+ },
+
+ finishEditStatusMessage(aSave) {
+ clearTimeout(this._stopEditStatusTimeout);
+ delete this._stopEditStatusTimeout;
+ let statusMessage = document.getElementById("statusMessageLabel");
+ let statusMessageInput = document.getElementById("statusMessageInput");
+ statusMessage.removeAttribute("hidden");
+ statusMessageInput.toggleAttribute("hidden", "true");
+ if (aSave) {
+ let newStatus = Ci.imIStatusInfo.STATUS_UNKNOWN;
+ if ("_statusTypeEditing" in this) {
+ let statusType = this._statusTypeEditing;
+ if (statusType == "available") {
+ newStatus = Ci.imIStatusInfo.STATUS_AVAILABLE;
+ } else if (statusType == "unavailable") {
+ newStatus = Ci.imIStatusInfo.STATUS_UNAVAILABLE;
+ } else if (statusType == "offline") {
+ newStatus = Ci.imIStatusInfo.STATUS_OFFLINE;
+ }
+ delete this._statusTypeBeforeEditing;
+ delete this._statusTypeEditing;
+ }
+ // apply the new status only if it is different from the current one
+ if (
+ newStatus != Ci.imIStatusInfo.STATUS_UNKNOWN ||
+ statusMessageInput.value != statusMessageInput.getAttribute("value")
+ ) {
+ IMServices.core.globalUserStatus.setStatus(
+ newStatus,
+ statusMessageInput.value
+ );
+ }
+ } else if ("_statusTypeBeforeEditing" in this) {
+ this.displayStatusType(this._statusTypeBeforeEditing);
+ delete this._statusTypeBeforeEditing;
+ delete this._statusTypeEditing;
+ }
+
+ if (statusMessage.hasAttribute("usingDefault")) {
+ statusMessage.setAttribute(
+ "value",
+ statusMessage.getAttribute("usingDefault")
+ );
+ }
+
+ statusMessageInput.removeAttribute("editing");
+ statusMessageInput.removeEventListener("blur", event => {
+ this.finishEditStatusMessage(true);
+ });
+
+ // We need to put the focus back on the label after the textbox
+ // binding has been detached, otherwise the focus gets lost (it's
+ // on none of the elements in the document), but before that we
+ // need to flush the layout.
+ statusMessageInput.getBoundingClientRect();
+ statusMessageInput.focus();
+ },
+
+ userIconClick() {
+ const nsIFilePicker = Ci.nsIFilePicker;
+ let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+ let bundle = Services.strings.createBundle(
+ "chrome://messenger/locale/chat.properties"
+ );
+ fp.init(
+ window,
+ bundle.GetStringFromName("userIconFilePickerTitle"),
+ nsIFilePicker.modeOpen
+ );
+ fp.appendFilters(nsIFilePicker.filterImages);
+ fp.open(rv => {
+ if (rv != nsIFilePicker.returnOK || !fp.file) {
+ return;
+ }
+ IMServices.core.globalUserStatus.setUserIcon(fp.file);
+ });
+ },
+
+ displayNameClick() {
+ let displayName = document.getElementById("displayName");
+ let displayNameInput = document.getElementById("displayNameInput");
+ displayName.setAttribute("hidden", "true");
+ displayNameInput.removeAttribute("hidden");
+ if (!displayNameInput.hasAttribute("editing")) {
+ displayNameInput.setAttribute("editing", "true");
+ if (displayName.hasAttribute("usingDefault")) {
+ displayNameInput.removeAttribute("value");
+ } else {
+ displayNameInput.setAttribute(
+ "value",
+ displayName.getAttribute("value")
+ );
+ }
+ displayNameInput.addEventListener("keypress", this.displayNameKeyPress);
+ displayNameInput.addEventListener("blur", event => {
+ this.finishEditDisplayName(true);
+ });
+ // force binding attachment by forcing layout
+ displayNameInput.getBoundingClientRect();
+ displayNameInput.select();
+ }
+
+ this.displayNameRefreshTimer();
+ },
+
+ _stopEditDisplayNameTimeout: 0,
+ displayNameRefreshTimer() {
+ const timeBeforeAutoValidate = 20 * 1000;
+ clearTimeout(this._stopEditDisplayNameTimeout);
+ this._stopEditDisplayNameTimeout = setTimeout(
+ this.finishEditDisplayName,
+ timeBeforeAutoValidate,
+ true
+ );
+ },
+
+ displayNameKeyPress(aEvent) {
+ switch (aEvent.keyCode) {
+ case aEvent.DOM_VK_RETURN:
+ statusSelector.finishEditDisplayName(true);
+ break;
+
+ case aEvent.DOM_VK_ESCAPE:
+ statusSelector.finishEditDisplayName(false);
+ break;
+
+ default:
+ statusSelector.displayNameRefreshTimer();
+ }
+ },
+
+ finishEditDisplayName(aSave) {
+ clearTimeout(this._stopEditDisplayNameTimeout);
+ let displayName = document.getElementById("displayName");
+ let displayNameInput = document.getElementById("displayNameInput");
+ displayName.removeAttribute("hidden");
+ displayNameInput.toggleAttribute("hidden", "true");
+ // Apply the new display name only if it is different from the current one.
+ if (
+ aSave &&
+ displayNameInput.value != displayNameInput.getAttribute("value")
+ ) {
+ IMServices.core.globalUserStatus.displayName = displayNameInput.value;
+ } else if (displayName.hasAttribute("usingDefault")) {
+ displayName.setAttribute(
+ "value",
+ displayName.getAttribute("usingDefault")
+ );
+ }
+
+ displayNameInput.removeAttribute("editing");
+ displayNameInput.removeEventListener("keypress", this.displayNameKeyPress);
+ displayNameInput.removeEventListener("blur", event => {
+ this.finishEditDisplayName(true);
+ });
+ },
+
+ init() {
+ let events = ["status-changed"];
+ statusSelector.displayCurrentStatus();
+
+ if (document.getElementById("displayName")) {
+ events.push("user-display-name-changed");
+ statusSelector.displayUserDisplayName();
+ }
+
+ if (document.getElementById("userIcon")) {
+ events.push("user-icon-changed");
+ statusSelector.displayUserIcon();
+ }
+
+ let statusMessage = document.getElementById("statusMessageLabel");
+ let statusMessageInput = document.getElementById("statusMessageInput");
+ if (statusMessage && statusMessageInput) {
+ statusMessage.addEventListener("keypress", this.statusMessageKeyPress);
+ statusMessageInput.addEventListener(
+ "keypress",
+ this.statusMessageKeyPress
+ );
+ }
+
+ for (let event of events) {
+ Services.obs.addObserver(statusSelector, event);
+ }
+ statusSelector._events = events;
+
+ window.addEventListener("unload", statusSelector.unload);
+ },
+
+ unload() {
+ for (let event of statusSelector._events) {
+ Services.obs.removeObserver(statusSelector, event);
+ }
+ },
+};