UX: puts back share-panel as floating pane on post actions (#7066)

UX: puts back share-panel as floating pane on post actions (#7066)

diff --git a/app/assets/javascripts/discourse/components/share-panel.js.es6 b/app/assets/javascripts/discourse/components/share-panel.js.es6
index 234e8d7..18a4801 100644
--- a/app/assets/javascripts/discourse/components/share-panel.js.es6
+++ b/app/assets/javascripts/discourse/components/share-panel.js.es6
@@ -1,15 +1,12 @@
 import { escapeExpression } from "discourse/lib/utilities";
-import { longDateNoYear } from "discourse/lib/formatter";
 import { default as computed } from "ember-addons/ember-computed-decorators";
 import Sharing from "discourse/lib/sharing";
 
 export default Ember.Component.extend({
   tagName: null,
 
-  date: Ember.computed.alias("panel.model.date"),
   type: Ember.computed.alias("panel.model.type"),
-  postNumber: Ember.computed.alias("panel.model.postNumber"),
-  postId: Ember.computed.alias("panel.model.postId"),
+
   topic: Ember.computed.alias("panel.model.topic"),
 
   @computed
@@ -17,21 +14,9 @@ export default Ember.Component.extend({
     return Sharing.activeSources(this.siteSettings.share_links);
   },
 
-  @computed("date")
-  postDate(date) {
-    return date ? longDateNoYear(new Date(date)) : null;
-  },
-
-  @computed("type", "postNumber", "postDate", "topic.title")
-  shareTitle(type, postNumber, postDate, topicTitle) {
+  @computed("type", "topic.title")
+  shareTitle(type, topicTitle) {
     topicTitle = escapeExpression(topicTitle);
-
-    if (type === "topic") {
-      return I18n.t("share.topic_html", { topicTitle });
-    }
-    if (postNumber) {
-      return I18n.t("share.post_html", { postNumber, postDate });
-    }
     return I18n.t("share.topic_html", { topicTitle });
   },
 
@@ -81,27 +66,10 @@ export default Ember.Component.extend({
 
   actions: {
     share(source) {
-      const url = source.generateUrl(
-        this.get("shareUrl"),
-        this.get("topic.title")
-      );
-      const options = {
-        menubar: "no",
-        toolbar: "no",
-        resizable: "yes",
-        scrollbars: "yes",
-        width: 600,
-        height: source.popupHeight || 315
-      };
-      const stringOptions = Object.keys(options)
-        .map(k => `${k}=${options[k]}`)
-        .join(",");
-
-      if (source.shouldOpenInPopup) {
-        window.open(url, "", stringOptions);
-      } else {
-        window.open(url, "_blank");
-      }
+      Sharing.shareSource(source, {
+        url: this.get("shareUrl"),
+        title: this.get("topic.title")
+      });
     }
   }
 });
diff --git a/app/assets/javascripts/discourse/components/share-popup.js.es6 b/app/assets/javascripts/discourse/components/share-popup.js.es6
new file mode 100644
index 0000000..5b0ff97
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/share-popup.js.es6
@@ -0,0 +1,173 @@
+import { wantsNewWindow } from "discourse/lib/intercept-click";
+import { longDateNoYear } from "discourse/lib/formatter";
+import computed from "ember-addons/ember-computed-decorators";
+import Sharing from "discourse/lib/sharing";
+import { nativeShare } from "discourse/lib/pwa-utils";
+
+export default Ember.Component.extend({
+  elementId: "share-link",
+  classNameBindings: ["visible"],
+  link: null,
+  visible: null,
+
+  @computed
+  sources() {
+    return Sharing.activeSources(this.siteSettings.share_links);
+  },
+
+  @computed("type", "postNumber")
+  shareTitle(type, postNumber) {
+    if (type === "topic") {
+      return I18n.t("share.topic");
+    }
+    if (postNumber) {
+      return I18n.t("share.post", { postNumber });
+    }
+    return I18n.t("share.topic");
+  },
+
+  @computed("date")
+  displayDate(date) {
+    return longDateNoYear(new Date(date));
+  },
+
+  _focusUrl() {
+    const link = this.get("link");
+    if (!this.capabilities.touch) {
+      const $linkInput = $("#share-link input");
+      $linkInput.val(link);
+
+      // Wait for the fade-in transition to finish before selecting the link:
+      window.setTimeout(() => $linkInput.select().focus(), 160);
+    } else {
+      const $linkForTouch = $("#share-link .share-for-touch a");
+      $linkForTouch.attr("href", link);
+      $linkForTouch.text(link);
+      const range = window.document.createRange();
+      range.selectNode($linkForTouch[0]);
+      window.getSelection().addRange(range);
+    }
+  },
+
+  _showUrl($target, url) {
+    const $currentTargetOffset = $target.offset();
+    const $this = this.$();
+
+    if (Ember.isEmpty(url)) {
+      return;
+    }
+
+    // Relative urls
+    if (url.indexOf("/") === 0) {
+      url = window.location.protocol + "//" + window.location.host + url;
+    }
+
+    const shareLinkWidth = $this.width();
+    let x = $currentTargetOffset.left - shareLinkWidth / 2;
+    if (x < 25) {
+      x = 25;
+    }
+    if (x + shareLinkWidth > $(window).width()) {
+      x -= shareLinkWidth / 2;
+    }
+
+    const header = $(".d-header");
+    let y = $currentTargetOffset.top - ($this.height() + 20);
+    if (y < header.offset().top + header.height()) {
+      y = $currentTargetOffset.top + 10;
+    }
+
+    $this.css({ top: "" + y + "px" });
+
+    if (!this.site.mobileView) {
+      $this.css({ left: "" + x + "px" });
+    }
+    this.set("link", encodeURI(url));
+    this.set("visible", true);
+
+    Ember.run.scheduleOnce("afterRender", this, this._focusUrl);
+  },
+
+  didInsertElement() {
+    this._super(...arguments);
+
+    const $html = $("html");
+    $html.on("mousedown.outside-share-link", e => {
+      // Use mousedown instead of click so this event is handled before routing occurs when a
+      // link is clicked (which is a click event) while the share dialog is showing.
+      if (this.$().has(e.target).length !== 0) {
+        return;
+      }
+      this.send("close");
+      return true;
+    });
+
+    $html.on(
+      "click.discourse-share-link",
+      "button[data-share-url], .post-info .post-date[data-share-url]",
+      e => {
+        // if they want to open in a new tab, let it so
+        if (wantsNewWindow(e)) {
+          return true;
+        }
+
+        e.preventDefault();
+
+        const $currentTarget = $(e.currentTarget);
+        const url = $currentTarget.data("share-url");
+        const postNumber = $currentTarget.data("post-number");
+        const postId = $currentTarget.closest("article").data("post-id");
+        const date = $currentTarget.children().data("time");
+
+        this.setProperties({ postNumber, date, postId });
+
+        // use native webshare only when the user clicks on the "chain" icon
+        if (!$currentTarget.hasClass("post-date")) {
+          nativeShare({ url }).then(null, () =>
+            this._showUrl($currentTarget, url)
+          );
+        } else {
+          this._showUrl($currentTarget, url);
+        }
+
+        return false;
+      }
+    );
+
+    $html.on("keydown.share-view", e => {
+      if (e.keyCode === 27) {
+        this.send("close");
+      }
+    });
+
+    this.appEvents.on("share:url", (url, $target) =>
+      this._showUrl($target, url)
+    );
+  },
+
+  willDestroyElement() {
+    this._super(...arguments);
+    $("html")
+      .off("click.discourse-share-link")
+      .off("mousedown.outside-share-link")
+      .off("keydown.share-view");
+  },
+
+  actions: {
+    close() {
+      this.setProperties({
+        link: null,
+        postNumber: null,
+        postId: null,
+        visible: false
+      });
+    },
+
+    share(source) {
+      Sharing.shareSource(source, {
+        url: this.get("link"),
+        title: this.get("topic.title")
+      });
+    }
+  }
+});
diff --git a/app/assets/javascripts/discourse/lib/sharing.js.es6 b/app/assets/javascripts/discourse/lib/sharing.js.es6
index cdd6ec5..4e57b9d 100644
--- a/app/assets/javascripts/discourse/lib/sharing.js.es6
+++ b/app/assets/javascripts/discourse/lib/sharing.js.es6
@@ -47,6 +47,27 @@ export default {
     _sources[source.id] = source;
   },
 
+  shareSource(source, data) {
+    const url = source.generateUrl(data.url, data.title);
+    const options = {
+      menubar: "no",
+      toolbar: "no",

[... diff too long, it was truncated ...]

GitHub sha: d04c4bf8