whimsical-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sam Ruby <ru...@apache.org>
Subject [whimsy.git] [23/50] Commit f919f22: search
Date Fri, 22 Jan 2016 02:40:55 GMT
Commit f919f22950f82d4ff19eb26f1ddc5b75bc8d8889:
    search


Branch: refs/heads/master
Author: Sam Ruby <rubys@intertwingly.net>
Committer: Sam Ruby <rubys@intertwingly.net>
Pusher: rubys <rubys@apache.org>

------------------------------------------------------------
main.rb                                                      | + 
public/stylesheets/app.css                                   | +++++ 
spec/other_views_spec.rb                                     | ++++++++++++++ 
views/app.js.rb                                              | + 
views/header.js.rb                                           | +++++ -
views/link.js.rb                                             | + -
views/main.html.rb                                           | ++ -
views/main.js.rb                                             | ++++++++ -----
views/search.js.rb                                           | ++++++++ 
------------------------------------------------------------
117 changes: 105 additions, 12 deletions.
------------------------------------------------------------


diff --git a/main.rb b/main.rb
index 5f2f1e6..be1f1c2 100755
--- a/main.rb
+++ b/main.rb
@@ -32,6 +32,7 @@
   Dir.chdir(FOUNDATION_BOARD) {@drafts = Dir['board_minutes_*.txt'].sort}
   @base = env['PATH_INFO'].chomp(path).untaint
   @path = path
+  @query = params['q']
   @agenda = "board_agenda_#{date.gsub('-','_')}.txt"
   pass unless File.exist? File.join(FOUNDATION_BOARD, @agenda)
 
diff --git a/public/stylesheets/app.css b/public/stylesheets/app.css
index 20bca72..d60d119 100644
--- a/public/stylesheets/app.css
+++ b/public/stylesheets/app.css
@@ -201,6 +201,11 @@ main hr {
 .search {padding-top: 1em}
 .hilite {background-color: #FF6}
 
+#search-text {
+  margin-left: 0.5em;
+  width: 95%;
+}
+
 #minute-comments {
   max-height: 9em;
   overflow: auto;
diff --git a/spec/other_views_spec.rb b/spec/other_views_spec.rb
new file mode 100644
index 0000000..632764a
--- /dev/null
+++ b/spec/other_views_spec.rb
@@ -0,0 +1,14 @@
+#
+# Other views
+#
+
+require_relative 'spec_helper'
+
+feature 'other reports' do
+  it "should support search" do
+    visit '/2015-02-18/search?q=ruby'
+
+    expect(page).to have_selector 'pre', text: 'Sam Ruby'
+    expect(page).to have_selector 'h4 a', text: 'Qpid'
+  end
+end
diff --git a/views/app.js.rb b/views/app.js.rb
index 4f20e49..b890814 100644
--- a/views/app.js.rb
+++ b/views/app.js.rb
@@ -6,6 +6,7 @@
 # Individual pages
 require_relative 'index'
 require_relative 'report'
+require_relative 'search'
 
 # Common elements
 require_relative 'link'
diff --git a/views/header.js.rb b/views/header.js.rb
index d179e82..0b0f520 100644
--- a/views/header.js.rb
+++ b/views/header.js.rb
@@ -60,11 +60,15 @@ def render
           end
 
           _ul.dropdown_menu do
-            _li { _Link text: 'Agenda', href: '' }
+            _li { _Link text: 'Agenda', href: '.' }
 
             Agenda.index.each do |item|
               _li { _Link text: item.index, href: item.href } if item.index
             end
+
+            _li.divider
+
+            _li { _Link text: 'Search', href: 'search' }
           end
         end
 
diff --git a/views/link.js.rb b/views/link.js.rb
index fb4baef..6da510c 100644
--- a/views/link.js.rb
+++ b/views/link.js.rb
@@ -26,7 +26,7 @@ def render
 
   def click(event)
     href = event.target.getAttribute('href')
-    unless href.start_with? '.'
+    if href =~ /^(\.|[-\w]+)$/
       Main.navigate href
       return false
     end
diff --git a/views/main.html.rb b/views/main.html.rb
index 21fec60..3713fcb 100755
--- a/views/main.html.rb
+++ b/views/main.html.rb
@@ -13,6 +13,7 @@
 
   _script src: '../app.js'
   _.render '#main' do
-    _Main parsed: @parsed, agenda: @agenda, agendas: @agendas, path: @path
+    _Main parsed: @parsed, agenda: @agenda, agendas: @agendas, path: @path,
+      query: @query
   end
 end
diff --git a/views/main.js.rb b/views/main.js.rb
index 285a597..98da911 100644
--- a/views/main.js.rb
+++ b/views/main.js.rb
@@ -1,6 +1,8 @@
 class Main < React
-  def route(path)
-    if path
+  def route(path, query)
+    if path == 'search'
+      @item = {title: 'Search', view: Search, color: 'blank', query: query}
+    elsif path and path != '.'
       @item = Agenda.find(path)
     else
       @item = Agenda
@@ -21,27 +23,31 @@ def componentWillMount()
     Agenda.load(@@parsed)
     Agenda._date = @@agenda[/(\d+_\d+_\d+)/, 1].gsub('_', '-')
     Agenda._agendas = @@agendas
-    self.route(@@path)
+    self.route(@@path, @@query)
   end
 
-  def navigate(path)
-    self.route(path)
-    history.pushState({path: path}, nil, path)
+  def navigate(path, query)
+    self.route(path, query)
+    history.pushState({path: path, query: query}, nil, path)
   end
 
   def componentDidMount()
     # export navigate method
     Main.navigate = self.navigate
 
-    history.replaceState({path: @@path}, nil, @@path)
+    if not history.state or not history.state.query
+      history.replaceState({path: @@path}, nil, @@path)
+    end
 
     window.addEventListener :popstate do |event|
-      if event.state and event.state.path
-        self.route(event.state.path)
+      if event.state and defined? event.state.path
+        self.route(event.state.path, event.state.query)
       end
     end
 
     def (document.getElementsByTagName('body')[0]).onkeyup(event)
+      return if document.getElementById('search-text')
+
       if event.keyCode == 37
         self.navigate document.querySelector("a[rel=prev]").getAttribute('href')
       elsif event.keyCode == 39
diff --git a/views/search.js.rb b/views/search.js.rb
new file mode 100644
index 0000000..27c33b6
--- /dev/null
+++ b/views/search.js.rb
@@ -0,0 +1,61 @@
+class Search < React
+  def initialize
+    @text = @@data.query || ''
+  end
+
+  def render
+    _div.search do
+      _label 'Search:', for: 'search_text'
+      _input.search_text! autofocus: 'autofocus', value: @text, 
+        onInput: self.input
+    end
+
+    if @text.length > 2
+      matches = false
+      text = @text.downcase()
+
+      Agenda.index.each do |item|
+        next unless item.text and item.text.downcase().include? text
+        matches = true
+
+        _section do
+          _h4 {_Link text: item.title, href: item.href}
+
+          item.text.split(/\n\s*\n/).each do |paragraph|
+            if paragraph.downcase().include? text
+              paragraph = paragraph.gsub('&', '&amp;').gsub('>', '&gt;').
+                gsub('<', '&lt;')
+
+              _pre.report dangerouslySetInnerHTML: {
+                __html: paragraph.gsub(/(#{text})/i,
+                 "<span class='hilite'>$1</span>")
+              }
+            end
+          end
+        end
+      end
+
+      _p {_em 'No matches'} unless matches
+    else
+      _p 'Please enter at least three characters'
+    end
+  end
+
+  def input(event)
+    @text = event.target.value
+  end
+
+  def componentDidMount()
+    self.componentDidUpdate()
+  end
+
+  def componentDidUpdate()
+    state = {path: 'search', query: @text}
+
+    if state.query
+      history.replaceState(state, nil, "search?q=#{encodeURIComponent(@text)}")
+    else
+      history.replaceState(state, nil, 'search')
+    end
+  end
+end

Mime
View raw message