浏览代码

Got filtering by site and query working

Markus Ochel 13 年之前
父节点
当前提交
bd90fc74a9

+ 7 - 3
admin/controllers/authors.coffee

@@ -10,14 +10,18 @@ class Authors extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Author.bind 'change fetch', @render
+    # @active @render
+    Author.bind 'change refresh', @render
+    Spine.bind 'filterbox:change', @filter
 
   render: =>
     context = 
-      authors: Author.all()
+      authors: Author.filter(@filterObj)
     @el.html templates.render('authors.html', {}, context)
     @
 
+  filter: (@filterObj) =>
+    @render()
+
 
 module.exports = Authors

+ 7 - 3
admin/controllers/blocks.coffee

@@ -10,14 +10,18 @@ class Blocks extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Block.bind 'change fetch', @render
+    # @active @render
+    Block.bind 'change refresh', @render
+    Spine.bind 'filterbox:change', @filter
 
   render: =>
     context = 
-      blocks: Block.all()
+      blocks: Block.filter(@filterObj)
     @el.html templates.render('blocks.html', {}, context)
     @
 
+  filter: (@filterObj) =>
+    @render()
+
 
 module.exports = Blocks

+ 8 - 4
admin/controllers/collections.coffee

@@ -2,7 +2,7 @@ Spine       = require('spine/core')
 # $           = Spine.$
 templates   = require('duality/templates')
 
-Collection       = require('models/collection')
+Collection  = require('models/collection')
 
 
 class Collections extends Spine.Controller
@@ -10,14 +10,18 @@ class Collections extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Collection.bind 'change fetch', @render
+    # @active @render
+    Collection.bind 'change refresh', @render
+    Spine.bind 'filterbox:change', @filter
 
   render: =>
     context = 
-      collections: Collection.all()
+      collections: Collection.filter(@filterObj)
     @el.html templates.render('collections.html', {}, context)
     @
 
+  filter: (@filterObj) =>
+    @render()
+
 
 module.exports = Collections

+ 7 - 3
admin/controllers/contacts.coffee

@@ -10,14 +10,18 @@ class Contacts extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Contact.bind 'change fetch', @render
+    # @active @render
+    Contact.bind 'change refresh', @render
+    Spine.bind 'filterbox:change', @filter
 
   render: =>
     context = 
-      contacts: Contact.all()
+      contacts: Contact.filter(@filterObj)
     @el.html templates.render('contacts.html', {}, context)
     @
 
+  filter: (@filterObj) =>
+    @render()
+
 
 module.exports = Contacts

+ 2 - 2
admin/controllers/dashboard.coffee

@@ -9,8 +9,8 @@ class Dashboard extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Essay.bind 'change fetch', @render
+    # @active @render
+    Essay.bind 'change refresh', @render
 
   render: =>
     context = 

+ 7 - 3
admin/controllers/essays.coffee

@@ -10,14 +10,18 @@ class Essays extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Essay.bind 'change fetch', @render
+    # @active @render
+    Essay.bind 'change refresh', @render
+    Spine.bind 'filterbox:change', @filter
 
   render: =>
     context = 
-      essays: Essay.all()
+      essays: Essay.filter(@filterObj)
     @el.html templates.render('essays.html', {}, context)
     @
 
+  filter: (@filterObj) =>
+    @render()
+
 
 module.exports = Essays

+ 49 - 0
admin/controllers/filter-box.coffee

@@ -0,0 +1,49 @@
+Spine       = require('spine/core')
+# $           = Spine.$
+templates   = require('duality/templates')
+
+Site  = require('models/site')
+
+
+class FilterBox extends Spine.Controller
+  className: 'filter-box'
+
+  constructor: ->
+    super
+    @siteId = ''
+    @query = ''
+    Site.bind 'change refresh', @render
+
+  render: =>
+    context = 
+      sites: Site.all()
+    @el.html templates.render('filter-box.html', {}, context)
+    @setup()
+    @
+
+  setup: ->
+    @filterInput = $(@el).find('input.filter-input')
+    @selectedSite = $(@el).find('.selected-site')
+    @siteSelector = $(@el).find('ul.site-selector')
+    
+    @filterInput.on 'keyup', (e) =>
+      @filter()
+    
+    @selectedSite.on 'click', (e) =>
+      @siteSelector.toggle()
+    
+    @siteSelector.find('li').on 'click', (e) =>
+      $item = $(e.currentTarget)
+      @selectedSite.find('> span').html($item.html())
+      @siteId = $item.attr('data-id')
+      @siteSelector.hide()
+      @filter()
+
+  filter: =>
+    @query = @filterInput.val()
+    Spine.trigger 'filterbox:change',
+      query: @query
+      siteId: @siteId
+
+
+module.exports = FilterBox

+ 7 - 0
admin/controllers/main-nav.coffee

@@ -9,10 +9,17 @@ class MainNav extends Spine.Controller
   constructor: ->
     super
     @render()
+    @setup()
 
   render: =>
     @el.html templates.render('main-nav.html', {}, {})
     @
 
+  setup: =>
+    links = @el.find('li a')
+    links.on 'click', (e) ->
+      links.removeClass('active')
+      $(@).addClass('active')
+
 
 module.exports = MainNav

+ 7 - 0
admin/controllers/main-stack.coffee

@@ -9,6 +9,8 @@ Blocks      = require('controllers/blocks')
 Contacts    = require('controllers/contacts')
 Sponsors    = require('controllers/sponsors')
 
+FilterBox   = require('controllers/filter-box')
+
 
 class MainStack extends Spine.Stack
   className: 'main stack'
@@ -35,6 +37,11 @@ class MainStack extends Spine.Stack
     '/contacts':    'contacts'
     '/sponsors':    'sponsors'
 
+  constructor: ->
+    super
+    @filterBox = new FilterBox
+    @append @filterBox
+
 
 module.exports = MainStack
     

+ 7 - 3
admin/controllers/sites.coffee

@@ -10,14 +10,18 @@ class Sites extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Site.bind 'change fetch', @render
+    # @active @render
+    Site.bind 'change refresh', @render
+    Spine.bind 'filterbox:change', @filter
 
   render: =>
     context = 
-      sites: Site.all()
+      sites: Site.filter(@filterObj)
     @el.html templates.render('sites.html', {}, context)
     @
 
+  filter: (@filterObj) =>
+    @render()
+
 
 module.exports = Sites

+ 7 - 3
admin/controllers/sponsors.coffee

@@ -10,14 +10,18 @@ class Sponsors extends Spine.Controller
 
   constructor: ->
     super
-    @active @render
-    Sponsor.bind 'change fetch', @render
+    # @active @render
+    Sponsor.bind 'change refresh', @render
+    Spine.bind 'filterbox:change', @filter
 
   render: =>
     context = 
-      sponsors: Sponsor.all()
+      sponsors: Sponsor.filter(@filterObj)
     @el.html templates.render('sponsors.html', {}, context)
     @
 
+  filter: (@filterObj) =>
+    @render()
+
 
 module.exports = Sponsors

+ 4 - 3
admin/models/author.coffee

@@ -1,13 +1,14 @@
 Spine = require('spine/core')
 require('lib/spine-couch-ajax')
 
-class Author extends Spine.Model
+BaseModel = require('models/base')
+
+class Author extends BaseModel
   @configure "Author", "site", "name", "email", "bio", "links", "photo"
   
   @extend Spine.Model.CouchAjax
   
-  @nameSort: (a, b) ->
-    if a.name > b.name then 1 else -1
+  @queryOn: ['name','email']
     
   validate: ->
     return 'Name is required' unless @name

+ 32 - 0
admin/models/base.coffee

@@ -0,0 +1,32 @@
+Spine = require('spine/core')
+
+class BaseModel extends Spine.Model 
+
+  @nameSort: (a, b) ->
+    if a.name > b.name then 1 else -1
+
+  @titleSort: (a, b) ->
+    if a.title > b.title then 1 else -1
+
+  @queryOn: ['name','title']
+
+  @filter: (obj) ->
+    return @all() unless obj
+    query = obj.query.toLowerCase()
+    siteId = obj.siteId.toLowerCase()
+    @select (item) =>
+      # See if matching any of the properties to filter on
+      matchedQuery = false
+      for p in @queryOn
+        matchedQuery = matchedQuery or item[p]?.toLowerCase().indexOf(query) isnt -1
+      matchedSite = if siteId and item.site then item.site is siteId else true
+      if query and siteId
+        matchedQuery and matchedSite
+      else if query
+        matchedQuery
+      else if siteId
+        matchedSite
+      else
+        true
+
+module.exports = BaseModel

+ 5 - 3
admin/models/block.coffee

@@ -1,15 +1,17 @@
 Spine = require('spine/core')
 require('lib/spine-couch-ajax')
 
-class Block extends Spine.Model
+BaseModel = require('models/base')
+
+class Block extends BaseModel
   @configure "Block", "site", "code", "name", "content"
   
   @extend Spine.Model.CouchAjax
   
-  @nameSort: (a, b) ->
-    if a.name > b.name then 1 else -1
+  @queryOn: ['name','code']
     
   validate: ->
     return 'Name is required' unless @name
+    return 'Code is required' unless @code
 
 module.exports = Block

+ 6 - 5
admin/models/collection.coffee

@@ -1,13 +1,14 @@
 Spine = require('spine/core')
 require('lib/spine-couch-ajax')
 
-class Collection extends Spine.Model
+BaseModel = require('models/base')
+
+class Collection extends BaseModel
   @configure "Collection", "site", "slug", "name", "intro"
-  
+
   @extend Spine.Model.CouchAjax
-  
-  @nameSort: (a, b) ->
-    if a.name > b.name then 1 else -1
+
+  @queryOn: ['name','slug']
     
   validate: ->
     return 'Site is required' unless @site

+ 4 - 3
admin/models/contact.coffee

@@ -1,13 +1,14 @@
 Spine = require('spine/core')
 require('lib/spine-couch-ajax')
 
-class Contact extends Spine.Model
+BaseModel = require('models/base')
+
+class Contact extends BaseModel
   @configure "Contact", "name", "email", "note"
   
   @extend Spine.Model.CouchAjax
   
-  @nameSort: (a, b) ->
-    if a.name > b.name then 1 else -1
+  @queryOn: ['name','email']
     
   validate: ->
     return 'Name is required' unless @name

+ 5 - 1
admin/models/essay.coffee

@@ -1,13 +1,17 @@
 Spine = require('spine/core')
 require('lib/spine-couch-ajax')
 
-class Essay extends Spine.Model
+BaseModel = require('models/base')
+
+class Essay extends BaseModel
   @configure "Essay", "site", "slug", "title", "intro", "body", "published", "published_at", "updated_at", "author_id", "sponsor_id", "collections"
   
   @extend Spine.Model.CouchAjax
   
   @titleSort: (a, b) ->
     if (a.title or a.published_at) > (b.title or b.published_at) then 1 else -1
+
+  @queryOn: ['title','slug']
     
   validate: ->
     return 'Site is required' unless @site

+ 4 - 3
admin/models/site.coffee

@@ -1,13 +1,14 @@
 Spine = require('spine/core')
 require('lib/spine-couch-ajax')
 
-class Site extends Spine.Model
+BaseModel = require('models/base')
+
+class Site extends BaseModel
   @configure "Site", "name", "name_html", "tagline", "footer_html", "link", "theme", "css", "google_analytics_code"
   
   @extend Spine.Model.CouchAjax
   
-  @nameSort: (a, b) ->
-    if a.name > b.name then 1 else -1
+  @queryOn: ['name','tagline','id']
     
   validate: ->
     return 'Name is required' unless @name

+ 5 - 4
admin/models/sponsor.coffee

@@ -1,13 +1,14 @@
 Spine = require('spine/core')
 require('lib/spine-couch-ajax')
 
-class Sponsor extends Spine.Model
+BaseModel = require('models/base')
+
+class Sponsor extends BaseModel
   @configure "Sponsor", "format", "name", "link", "label", "content", "note", "contact_id"
   
   @extend Spine.Model.CouchAjax
-  
-  @nameSort: (a, b) ->
-    if a.name > b.name then 1 else -1
+
+  @queryOn: ['name','content','link','format']
     
   validate: ->
     @format ?= 'text'

+ 26 - 0
admin/static/css/mixin.styl

@@ -88,6 +88,32 @@ transform(tr)
 hacel()
   transform(translate3d(0,0,0))
 
+arrow(direction = 'right', size = 10px, color = #666, width = 0.53em, length = 1em)
+  /*
+   * In Internet Explorer, The"border-style: dashed" will never be
+   * rendered unless "(width * 5) >= border-width" is true.
+   * Since "width" is set to "0", the "dashed-border" remains
+   * invisible to the user, which renders the border just like how
+   * "border-color: transparent" renders.
+   */
+  border-style: dashed
+  border-color: transparent
+  border-width: width
+  display: -moz-inline-box
+  display: inline-block
+  /* Use font-size to control the size of the arrow. */
+  font-size: size
+  height: 0
+  line-height: 0
+  position: relative
+  vertical-align: middle
+  width: 0
+  
+  border-{direction}-width: length;
+  border-{direction}-style: solid;
+  border-{direction}-color: color;
+  {direction}: 0.25em;
+
 clearfix()
   *zoom: 1
   &:before, &:after

+ 77 - 3
admin/static/css/theme.styl

@@ -33,6 +33,7 @@ h1, h2, h3, h4, h5, h6
   color: darken($textColor, 4%)
   font-weight: 300
   line-height: 1.2em
+  margin: 0
 
 h1
   font-size: 3.5em
@@ -100,6 +101,17 @@ img
   display: block
   border: 0
 
+input, textarea
+  color: $textColor
+  font-size: 1em
+  font-weight: 300
+  padding: 5px 10px
+  margin: 0.5em 0
+  border: 1px solid #f3f3f3
+
+::-webkit-input-placeholder
+  color: #f3f3f3
+
 #app
   position: absolute
   top: 0
@@ -109,7 +121,7 @@ img
 
 .site-name
   margin: 0 0 0.8em -0.05em
-  font-size: 5.25em
+  font-size: 1.65em
   line-height: 0.8em
   font-weight: 300
   color: $lightGrey
@@ -125,6 +137,59 @@ span.label
   font-weight: 300
   color: $lightGrey
 
+.filter-box
+  position: absolute
+  top: 20px
+  right: 30px
+  width: 30%
+
+  .filter-input
+    display: block
+    width: 100%
+    color: $lightGrey
+    font-size: 1.5em
+    font-weight: 300
+    padding: 5px 10px
+    margin: 0
+    border: 1px solid #f3f3f3
+    outline: none
+
+  .selected-site
+    padding: 5px 5px 5px 10px
+    border: 1px solid #f3f3f3
+    border-top: 0
+    line-height: 1em
+    cursor: pointer
+    -webkit-user-select: none
+
+    .icon
+      float: right
+      margin: 1px 0 0 0
+      arrow('top', 10px, $lightGrey)
+
+    &:hover
+      background: #f3f3f3
+
+  ul.site-selector
+    display: none
+    list-style-type: none
+    margin: 0
+    padding: 0
+    background: #fff
+    border: 1px solid #f3f3f3
+    border-top: 0
+    max-height: 500px
+    overflow: auto
+    -webkit-user-select: none
+
+    li
+      padding: 10px 20px
+      cursor: pointer
+
+      &:hover
+        background: #f3f3f3
+
+
 .main.navbar
   position: absolute
   top: 0
@@ -135,6 +200,7 @@ span.label
   margin: 0
   background: $primaryColor
   overflow: auto
+  -webkit-user-select: none
 
   .app-logo
     padding: 16px 18px
@@ -147,6 +213,9 @@ span.label
     word-spacing: 0em
     white-space: nowrap
 
+    a
+      color: #fff
+
   > ul
     list-style-type: none
     padding: 0
@@ -164,6 +233,9 @@ span.label
         &:hover
           background: darken($primaryColor, 5%)
 
+        &.active
+          background: darken($primaryColor, 10%)
+
 
 .main.stack
   position: absolute
@@ -185,7 +257,7 @@ span.label
     padding: 20px 30px
 
     > h1
-      margin-bottom: 20px
+      margin: 0 0 20px 0
 
       .count
         color: $lightGrey
@@ -197,6 +269,7 @@ span.label
       margin: 0
       padding: 0
       border-top: 1px dotted #f3f3f3
+      clearfix()
 
       > li
         font-size: 1.5em
@@ -234,7 +307,7 @@ span.label
             &:hover
               text-decoration: underline
 
-.stack > *:not(.active)
+.stack > .panel:not(.active)
   display: none
 
 
@@ -248,3 +321,4 @@ span.label
         font-size: 0.75em
         line-height: 1em
         color: $lightGrey
+

+ 11 - 0
admin/templates/filter-box.html

@@ -0,0 +1,11 @@
+<input class="filter-input" type="text" value="" placeholder="filter">
+<div class="selected-site">
+  <i class="icon"></i>
+  <span>All sites</span>
+</div>
+<ul class="site-selector">
+  <li data-id="">All sites</li>
+  {{#each sites}}
+  <li data-id="{{_id}}">{{{name_html}}}</li>
+  {{/each}}
+</ul>

+ 2 - 2
admin/templates/main-nav.html

@@ -1,6 +1,6 @@
-<div class="app-logo">kleks</div>
+<div class="app-logo"><a href="/">kleks</a></div>
 <ul>
-  <li class="dashboard"><a href="#/">Dashboard</a></li>
+  <li class="dashboard"><a class="active" href="#/">Dashboard</a></li>
   <li class="sites"><a href="#/sites">Sites</a></li>
   <li class="authors"><a href="#/authors">Authors</a></li>
   <li class="collections"><a href="#/collections">Collections</a></li>

+ 4 - 1
admin/templates/sites.html

@@ -5,7 +5,10 @@
     <div class="actions">
       <div><a href="{{link}}" target="_blank">{{_id}}</span></div>
     </div>
-    <a href="#/{{type}}/{{_id}}/edit">{{name}}</a>
+    <a class="site-name" href="#/{{type}}/{{_id}}/edit">{{{name_html}}}</a>
+    <div class="meta">
+      {{#if tagline}}<div>{{{tagline}}}</div>{{/if}}
+    </div>
   </li>
   {{/each}}
 </ul>