From 75df6f42097da1a7efe4a5a5be0ebe20ae89164e Mon Sep 17 00:00:00 2001
From: goldpbear <tcroxson@gmail.com>
Date: Thu, 30 Mar 2017 20:50:41 -0700
Subject: [PATCH] Accommodate variable dataset slugs in social media sharing
 functionality

---
 .../place-detail-promotion-bar.html           |  4 +-
 src/base/static/js/handlebars-helpers.js      |  8 ---
 src/base/static/js/routes.js                  |  1 +
 src/base/static/js/utils.js                   | 61 +++++++++++++++++++
 src/base/static/js/views/place-detail-view.js | 12 +++-
 src/base/static/js/views/place-list-view.js   | 10 +++
 src/base/static/scss/_content.scss            | 18 +++---
 src/base/templates/base.html                  |  1 +
 src/flavors/duwamish_flavor/config.yml        |  3 +
 .../duwamish_flavor/templates/index.html      | 48 +++++----------
 10 files changed, 111 insertions(+), 55 deletions(-)

diff --git a/src/base/jstemplates/place-detail-promotion-bar.html b/src/base/jstemplates/place-detail-promotion-bar.html
index cc5d3fc70b..ba25552d26 100644
--- a/src/base/jstemplates/place-detail-promotion-bar.html
+++ b/src/base/jstemplates/place-detail-promotion-bar.html
@@ -2,8 +2,8 @@
           <div class="support {{#if story}}single-line{{/if}}"></div>
           <div class="social {{#if story}}single-line{{/if}}">
             <ul class="sharing unstyled-list">
-              <li class="share-link share-twitter"><a href="https://twitter.com/intent/tweet?url={{ place_url id }}&text={{ name }}" target="_blank" data-shareto="twitter">{{#_}}Tweet This{{/_}}</a></li>
-              <li class="share-link share-facebook"><a href="https://www.facebook.com/sharer/sharer.php?u={{ place_url id }}" target="_blank" data-shareto="facebook">{{#_}}Recommend on Facebook{{/_}}</a></li>
+              <li class="share-link share-twitter">{{#_}}Tweet This{{/_}}</li>
+              <li class="share-link share-facebook">{{#_}}Recommend on Facebook{{/_}}</li>
             </ul>
           </div>
         </section>
diff --git a/src/base/static/js/handlebars-helpers.js b/src/base/static/js/handlebars-helpers.js
index b10aa6587e..11134b4bd0 100644
--- a/src/base/static/js/handlebars-helpers.js
+++ b/src/base/static/js/handlebars-helpers.js
@@ -253,14 +253,6 @@
     return result;
   });
 
-  Handlebars.registerHelper('place_url', function(place_id) {
-    var l = window.location,
-        protocol = l.protocol,
-        host = l.host;
-
-    return [protocol, '//', host, '/place/', place_id].join('');
-  });
-
 // Get the current url
 Handlebars.registerHelper('windowLocation', function(place_id) {
   return window.location;
diff --git a/src/base/static/js/routes.js b/src/base/static/js/routes.js
index f76bfd8893..2e580372a1 100644
--- a/src/base/static/js/routes.js
+++ b/src/base/static/js/routes.js
@@ -106,6 +106,7 @@ Shareabouts.Util = Util;
 
       this.appView = new AppView({
         el: 'body',
+        appConfig: options.appConfig,
         activities: this.activities,
         places: this.places,
         landmarks: this.landmarks,
diff --git a/src/base/static/js/utils.js b/src/base/static/js/utils.js
index 3188afad56..546be5725a 100644
--- a/src/base/static/js/utils.js
+++ b/src/base/static/js/utils.js
@@ -29,6 +29,67 @@ var self = module.exports = {
       }
     },
 
+    // Given a model, update social media meta tags with the model's information,
+    // or generic information from the appConfig as a fallback.
+    updateSocialMetaTags: function(model, appConfig) {
+      var siteName = appConfig.title,
+          title = model.get("title") ||
+                  model.get("name") || 
+                  appConfig.title,
+          description = model.get("description") || 
+                        appConfig.meta_description,
+          imgSrc = (model.get("attachments").length > 0) ?
+                    model.get("attachments")[0].file :
+                    appConfig.thumbnail,
+          submitter = model.get("submitter");
+
+      // Twitter meta tags
+      $("meta[name='twitter:title']").attr("content", title);
+      $("meta[name='twitter:description']").attr("content", description);
+      $("meta[name='twitter:img:src']").attr("content", imgSrc);
+      $("meta[name='twitter:creator']").attr("content", submitter);
+
+      // Facebook meta tags
+      $("meta[name='og:site_name']").attr("content", siteName);
+      $("meta[name='og:title']").attr("content", title);
+      $("meta[name='og:description']").attr("content", description);
+      $("meta[name='og:image']").attr("content", imgSrc);
+
+      return title;
+    },
+
+    getPathname: function(model) {
+      if (model.get("url-title")) {
+        return model.get("url-title");
+      } else if (model.get("datasetSlug")) {
+        return model.get("datasetSlug") + "/" + model.get("id");
+      } else {
+        return model.get("id");
+      }
+    },
+
+    onSocialShare: function(model, service) {
+      var appConfig = Shareabouts.Config.app,
+          title = this.updateSocialMetaTags(model, appConfig),
+          protocol = window.location.protocol,
+          host = window.location.host,
+          pathname = this.getPathname(model),
+          url = [protocol, "//", host, "/", pathname].join(""),
+          shareUrl;
+
+      if (service === "twitter") {
+        shareUrl = ["https://twitter.com/intent/tweet?url=",
+                    url,
+                    "&text=",
+                    title].join("");
+      } else if (service === "facebook") {
+        shareUrl = ["https://www.facebook.com/sharer/sharer.php?u=",
+                    url].join("");
+      }
+
+      window.open(shareUrl, "_blank");
+    },
+
     // Given the information provided in a url (that is, an id and possibly a slug),
     // attempt to find the corresponding model within all collections on the page.
     // Three conditions are possible:
diff --git a/src/base/static/js/views/place-detail-view.js b/src/base/static/js/views/place-detail-view.js
index 295dd54e6f..dd1e8bc1cf 100644
--- a/src/base/static/js/views/place-detail-view.js
+++ b/src/base/static/js/views/place-detail-view.js
@@ -8,7 +8,9 @@
   module.exports = Backbone.View.extend({
     events: {
       'click .place-story-bar .btn-previous-story-nav': 'onClickStoryPrevious',
-      'click .place-story-bar .btn-next-story-nav': 'onClickStoryNext'
+      'click .place-story-bar .btn-next-story-nav': 'onClickStoryNext',
+      'click .share-twitter': 'onShareTwitter',
+      'click .share-facebook': 'onShareFacebook'
     },
     initialize: function() {
       var self = this;
@@ -54,6 +56,14 @@
       });
     },
 
+    onShareTwitter: function() {
+      Util.onSocialShare(this.model, "twitter");
+    },
+
+    onShareFacebook: function() {
+      Util.onSocialShare(this.model, "facebook");
+    },
+
     onClickStoryPrevious: function() {
       this.options.router.navigate(this.model.attributes.story.previous, {trigger: true});
     },
diff --git a/src/base/static/js/views/place-list-view.js b/src/base/static/js/views/place-list-view.js
index 066e83ca52..7c66a6b395 100644
--- a/src/base/static/js/views/place-list-view.js
+++ b/src/base/static/js/views/place-list-view.js
@@ -22,6 +22,10 @@
       'hide': 'hide',
       'change': 'render'
     },
+    events: {
+      'click .share-twitter': 'onShareTwitter',
+      'click .share-facebook': 'onShareFacebook'
+    },
     initialize: function() {
       var supportType = Shareabouts.Config.support.submission_type;
 
@@ -37,6 +41,12 @@
         userToken: Shareabouts.Config.userToken
       });
     },
+    onShareTwitter: function() {
+      Util.onSocialShare(this.model, "twitter");
+    },
+    onShareFacebook: function() {
+      Util.onSocialShare(this.model, "facebook");
+    },
     onBeforeRender: function() {
       // if an attachmentCollection has models in it, make sure the place
       // model's attachment attribute is set for the attachments to be
diff --git a/src/base/static/scss/_content.scss b/src/base/static/scss/_content.scss
index ffcd399b5d..be6d0112cc 100644
--- a/src/base/static/scss/_content.scss
+++ b/src/base/static/scss/_content.scss
@@ -165,21 +165,19 @@ a.minimize-btn {
     float: right;
     padding: 0 !important;
     margin-left: 10px;
-
-    a {
-        display: block;
-        width: 32px;
-        height: 32px;
-        overflow: hidden;
-        text-indent: -9999px;
-    }
+    display: block;
+    width: 32px;
+    height: 32px;
+    overflow: hidden;
+    text-indent: -9999px;
+    cursor: pointer;
 }
 
-.share-twitter a {
+.share-twitter {
     background: url(images/twitter-32.png) 0 0 no-repeat scroll;
 }
 
-.share-facebook a {
+.share-facebook {
     background: url(images/facebook-32.png) 0 0 no-repeat scroll;
 }
 
diff --git a/src/base/templates/base.html b/src/base/templates/base.html
index f3a2659969..ae0021909b 100644
--- a/src/base/templates/base.html
+++ b/src/base/templates/base.html
@@ -304,6 +304,7 @@ <h3>
         'user:' + S.bootstrapped.currentUser.id :
         {{ user_token_json|safe }}),
 
+      app:        {{ config.app|as_json }},
       flavor:     {{ config.data|as_json }},
       place:      {{ config.place|as_json }},
       placeTypes: {{ config.place_types|as_json }},
diff --git a/src/flavors/duwamish_flavor/config.yml b/src/flavors/duwamish_flavor/config.yml
index 82c849cb02..168b68207d 100644
--- a/src/flavors/duwamish_flavor/config.yml
+++ b/src/flavors/duwamish_flavor/config.yml
@@ -9,6 +9,9 @@ app:
   # Meta author that will show up in Google search results
   meta_author: SmarterCleanup.org
 
+  # Fallback image to use for sharing on social services if no model image is present
+  thumbnail: /static/css/images/fb-thumbnail.png
+
   # When the map loads, existing places will be loaded in chunks. By default,
   # the size of the chunks will be a reasonable default dictated by the API
   # server. If you would like to override the chunk size, use this setting:
diff --git a/src/flavors/duwamish_flavor/templates/index.html b/src/flavors/duwamish_flavor/templates/index.html
index ae2b6a1bb0..9976f5c345 100644
--- a/src/flavors/duwamish_flavor/templates/index.html
+++ b/src/flavors/duwamish_flavor/templates/index.html
@@ -8,40 +8,20 @@
 {% endblock %}
 
 {% block meta %}
-  {% if place %}
-    <!-- Twitter -->
-    <meta name="twitter:widgets:csp" content="on"> <!--- # Added by LMS for SSL compatibility --->
-    <meta name="twitter:card" content="summary">
-    <meta name="twitter:title" content="{{ place.properties.name }}">
-    <meta name="twitter:description" content="{{ place.properties.description }}">
-    {% with attachment=place.properties.attachments|first %}
-    <meta name="twitter:image:src" content="{{ attachment.file }}">
-    {% endwith %}
-    {% comment %} TODO: Fill this in when we know if the username is from twitter
-      <meta name="twitter:creator" content="place.submitter.username">
-    {% endcomment %}
-
-    <!-- Facebook -->
-    <meta property="og:site_name" content="{{ config.app.title }}" />
-    <meta property="og:title" content="{{ place.properties.name }}" />
-    <meta property="og:description" content="{{ place.properties.description }}" />
-    {% with attachment=place.properties.attachments|first %}
-    <meta name="og:image" content="{{ attachment.file }}">
-    {% endwith %}
-  {% else %}
-    <!-- Twitter -->
-    <meta name="twitter:card" content="summary">
-    <meta name="twitter:title" content="{{ config.app.title }}">
-    <meta name="twitter:description" content="{{ config.app.meta_description }}">
-    <meta name="twitter:widgets:csp" content="on"> <!--- # Added by LMS for SSL compatibility --->
-
-    <!-- Facebook -->
-    <meta property="og:site_name" content="{{ config.app.title }}" />
-    <meta property="og:title" content="{{ config.app.title }}" />
-    <meta property="og:description" content="{{ config.app.meta_description }}" />
-    <meta name="og:image" content="{{STATIC_URL}}css/images/fb-thumbnail.png">
-
-  {% endif%}
+  <!-- NOTE: social meta tag content gets populated client-side. -->
+  <!-- Twitter -->
+  <meta name="twitter:card" content="summary">
+  <meta name="twitter:widgets:csp" content="on">
+  <meta name="twitter:title" content="">
+  <meta name="twitter:description" content="">
+  <meta name="twitter:image:src" content="">
+  <meta name="twitter:creator" content="">
+
+  <!-- Facebook -->
+  <meta property="og:site_name" content="" />
+  <meta property="og:title" content="" />
+  <meta property="og:description" content="" />
+  <meta name="og:image" content="">
 {% endblock %}
 
 <!--