From 742c5e29c9ce33c632ffb9a44d1bf276d50f992b Mon Sep 17 00:00:00 2001
From: Sam <sam.saffron@gmail.com>
Date: Sat, 18 Oct 2014 14:27:33 +1100
Subject: [PATCH] FEATURE: advanced search help

---
 .../discourse/controllers/search-help.js.es6          |  7 +++++++
 .../javascripts/discourse/lib/search-for-term.js.es6  |  6 ++++++
 .../javascripts/discourse/routes/application.js.es6   | 10 ++++++++++
 .../discourse/templates/modal/search_help.hbs         |  3 +++
 app/assets/javascripts/discourse/templates/search.hbs |  3 +++
 .../javascripts/discourse/views/search-help.js.es6    |  4 ++++
 app/assets/stylesheets/desktop/header.scss            | 11 +++++++++++
 app/assets/stylesheets/mobile/header.scss             |  5 +++++
 app/controllers/static_controller.rb                  |  5 +++++
 config/locales/client.en.yml                          |  4 ++++
 config/locales/server.en.yml                          | 11 +++++++++++
 lib/sass/discourse_sass_importer.rb                   |  2 +-
 12 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100644 app/assets/javascripts/discourse/controllers/search-help.js.es6
 create mode 100644 app/assets/javascripts/discourse/templates/modal/search_help.hbs
 create mode 100644 app/assets/javascripts/discourse/views/search-help.js.es6

diff --git a/app/assets/javascripts/discourse/controllers/search-help.js.es6 b/app/assets/javascripts/discourse/controllers/search-help.js.es6
new file mode 100644
index 000000000..821c431af
--- /dev/null
+++ b/app/assets/javascripts/discourse/controllers/search-help.js.es6
@@ -0,0 +1,7 @@
+import ModalFunctionality from 'discourse/mixins/modal-functionality';
+
+import DiscourseController from 'discourse/controllers/controller';
+
+export default DiscourseController.extend(ModalFunctionality, {
+  needs: ['modal']
+});
diff --git a/app/assets/javascripts/discourse/lib/search-for-term.js.es6 b/app/assets/javascripts/discourse/lib/search-for-term.js.es6
index 592195f72..7cd3fffb9 100644
--- a/app/assets/javascripts/discourse/lib/search-for-term.js.es6
+++ b/app/assets/javascripts/discourse/lib/search-for-term.js.es6
@@ -59,6 +59,12 @@ export default function searchForTerm(term, opts) {
       }
     });
 
+    // a bit awkward, but we need to get the help link in
+    // somehow
+    if(results.resultTypes && results.resultTypes[0]) {
+      results.resultTypes[0].showHelp = true;
+    }
+
     var noResults = !!(results.topics.length === 0 &&
                        results.posts.length === 0 &&
                        results.users.length === 0 &&
diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6
index c60977db1..29f036f13 100644
--- a/app/assets/javascripts/discourse/routes/application.js.es6
+++ b/app/assets/javascripts/discourse/routes/application.js.es6
@@ -90,6 +90,16 @@ var ApplicationRoute = Discourse.Route.extend({
       Discourse.Route.showModal(this, 'keyboardShortcutsHelp');
     },
 
+    showSearchHelp: function() {
+      var self = this;
+
+      // TODO: @EvitTrout how do we get a loading indicator here?
+      Discourse.ajax("/static/search_help.html", { dataType: 'html' }).then(function(html){
+        Discourse.Route.showModal(self, 'searchHelp', html);
+      });
+
+    },
+
 
     /**
       Close the current modal, and destroy its state.
diff --git a/app/assets/javascripts/discourse/templates/modal/search_help.hbs b/app/assets/javascripts/discourse/templates/modal/search_help.hbs
new file mode 100644
index 000000000..ace1db3e6
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/modal/search_help.hbs
@@ -0,0 +1,3 @@
+<div id="search-help" class="modal-body">
+  {{{model}}}
+</div>
diff --git a/app/assets/javascripts/discourse/templates/search.hbs b/app/assets/javascripts/discourse/templates/search.hbs
index ff8a6bdd4..dfd8048e6 100644
--- a/app/assets/javascripts/discourse/templates/search.hbs
+++ b/app/assets/javascripts/discourse/templates/search.hbs
@@ -22,6 +22,9 @@
                 <a href='#' class='filter' {{action "moreOfType" resultType.type bubbles=false}}>{{i18n show_more}} <i class="fa fa-chevron-down"></i></a>
             {{else}}
             {{/if}}
+            {{#if resultType.showHelp}}
+              <a href="#" class="show-help" {{action "showSearchHelp" bubbles=false}}>{{i18n show_help}}</a>
+            {{/if}}
         </div>
     {{/each}}
   {{else}}
diff --git a/app/assets/javascripts/discourse/views/search-help.js.es6 b/app/assets/javascripts/discourse/views/search-help.js.es6
new file mode 100644
index 000000000..4492fde70
--- /dev/null
+++ b/app/assets/javascripts/discourse/views/search-help.js.es6
@@ -0,0 +1,4 @@
+export default Discourse.ModalBodyView.extend({
+  templateName: 'modal/search_help',
+  title: I18n.t('search_help.title')
+});
diff --git a/app/assets/stylesheets/desktop/header.scss b/app/assets/stylesheets/desktop/header.scss
index b0821a9bc..8dfa245ee 100644
--- a/app/assets/stylesheets/desktop/header.scss
+++ b/app/assets/stylesheets/desktop/header.scss
@@ -71,3 +71,14 @@ and (max-width : 570px) {
 .d-dropdown .searching {
   right: 30px;
 }
+
+// leave room for scroll bar
+.d-dropdown input[type='text'] {
+  width: 505px;
+}
+
+.d-dropdown .no-results .show-help {
+  position: absolute;
+  right: 15px;
+}
+
diff --git a/app/assets/stylesheets/mobile/header.scss b/app/assets/stylesheets/mobile/header.scss
index 2f4599850..59736598c 100644
--- a/app/assets/stylesheets/mobile/header.scss
+++ b/app/assets/stylesheets/mobile/header.scss
@@ -74,3 +74,8 @@
 .search-link .topic-statuses .topic-status i {
   font-size: 14px;
 }
+
+.d-dropdown .no-results .show-help {
+  display: none;
+}
+
diff --git a/app/controllers/static_controller.rb b/app/controllers/static_controller.rb
index 3a452362c..4adda3cdc 100644
--- a/app/controllers/static_controller.rb
+++ b/app/controllers/static_controller.rb
@@ -35,6 +35,11 @@ class StaticController < ApplicationController
       return
     end
 
+    if I18n.exists?("static.#{@page}")
+      render text: PrettyText.cook(I18n.t("static.#{@page}")), layout: !request.xhr?, formats: [:html]
+      return
+    end
+
     file = "static/#{@page}.#{I18n.locale}"
     file = "static/#{@page}.en" if lookup_context.find_all("#{file}.html").empty?
     file = "static/#{@page}"    if lookup_context.find_all("#{file}.html").empty?
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 87fb3c871..f107118c9 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -117,6 +117,7 @@ en:
     admin_title: "Admin"
     flags_title: "Flags"
     show_more: "show more"
+    show_help: "help"
     links: "Links"
     links_lowercase: "links"
     faq: "FAQ"
@@ -2140,6 +2141,9 @@ en:
     lightbox:
       download: "download"
 
+    search_help:
+      title: 'Search Help'
+
     keyboard_shortcuts_help:
       title: 'Keyboard Shortcuts'
       jump_to:
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index f719d89f9..a7903fdd7 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -2120,3 +2120,14 @@ en:
       If we decide to change our privacy policy, we will post those changes on this page.
 
       This document is CC-BY-SA. It was last updated May 31, 2013.
+
+  static:
+    search_help: |
+      You may include special search operators in your terms, available operators are:
+
+      `order:latest` Results will be ordered by last post time (as opposed to relevence)  
+      `status:open` Only show open topics  
+      `status:closed` Only show closed topics  
+      `category:foo` Only show topics in the category `foo`  
+      
+      Example: `bears category:test status:open order:latest` will search for topics in the category bears that are not closed or archived ordered by last post date.
diff --git a/lib/sass/discourse_sass_importer.rb b/lib/sass/discourse_sass_importer.rb
index f2404cccb..26721cdbb 100644
--- a/lib/sass/discourse_sass_importer.rb
+++ b/lib/sass/discourse_sass_importer.rb
@@ -2,7 +2,7 @@
 # Sprockets::SassImporter implementation provided in sass-rails since that is used
 # during asset precompilation.
 class DiscourseSassImporter < Sass::Importers::Filesystem
-  GLOB = /\*|\[.+\]/
+  GLOB = /\*|\[.+\]/ unless defined? GLOB
 
   # Depending upon where this is passed we might either be passed a string as the
   # first argument or a sprockets context. If the first argument is a sprockets