carte-server 1.0.8 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 10e4c87356c4d71772d5534102215a6ebee7bfa6
4
- data.tar.gz: dd8e7c1fd85b46173178451cd93c113bec50f86f
3
+ metadata.gz: cd3f472fe4bb7d487fcdaed6f4ac9d6e4fcc55ae
4
+ data.tar.gz: c52db06dafe184f6a745ce5c678be0603b38e581
5
5
  SHA512:
6
- metadata.gz: 16593c18c820bc4a76eae61d999daf1fe18ec8b4f6d6d8f5f17846dda80e26c4e370efc770ccf6c0b885c1a6ab25cacd0b7f2de9ca44ea3a3c407f55ec58497c
7
- data.tar.gz: e9b46b510b2a640e17a2390f0a1e79f5fe9626bf0f6eee9c8637958031908716511a3db7fbe19e4689680bd2d776484371724fa059e141d8435863ae6fe6c50c
6
+ metadata.gz: 14e3089137ea1bd9b1048eb573679eb85f5d5117f6de0eccabff4acf27d8c6590a6816db20877edef2e424c99e6743107ffe9294076808f74628f64ec2350b92
7
+ data.tar.gz: 3cac1e649934df4c691bc351325b0eaf3d91ed0d9305c1fba54afdcda896334472351d4a7db0da650cf1804945e9ab85bc0f53d884830cf05e8c4e0bae6d04d6
@@ -0,0 +1,9 @@
1
+ Backbone = require('backbone')
2
+ config = require('../config')
3
+ querystring = require('querystring')
4
+ $ = require('jquery')
5
+
6
+ module.exports = class Tag extends Backbone.Model
7
+ modelName: 'Tag'
8
+ idAttribute: 'name'
9
+ url: ()-> config.root_path + config.api_path + '/tags/' + encodeURIComponent(@get('name')) + '.json'
@@ -0,0 +1,10 @@
1
+ Backbone = require('backbone')
2
+ Tag = require('./tag')
3
+ $ = require('jquery')
4
+ config = require('../config')
5
+
6
+ module.exports = class Tags extends Backbone.Collection
7
+ collectionName: 'Tags'
8
+ model: Tag
9
+ url: config.root_path + config.api_path + '/tags.json'
10
+ parse: (response)-> response.tags
@@ -3,10 +3,15 @@ Backbone = require('backbone')
3
3
 
4
4
  module.exports = class Router extends Backbone.Router
5
5
  routes:
6
+ 'tags': 'tags'
6
7
  '': 'list'
7
8
  ':title': 'show'
8
9
  ':title/history': 'history'
9
10
 
11
+ tags: ->
12
+ console.log '[router] tags'
13
+ @current = 'tags'
14
+
10
15
  list: (string)->
11
16
  console.log '[router] list', string
12
17
  location.hash = '/' if location.hash == ''
@@ -2,10 +2,12 @@
2
2
  $ = require('jquery')
3
3
  React = require('react')
4
4
  List = require('./list')
5
+ Tags = require('./tags')
5
6
  Slideshow = require('./slideshow')
6
7
  CardCollection = require('../models/cards')
7
8
  CardHistoryCollection = require('../models/card_histories')
8
9
  CardModel = require('../models/card')
10
+ TagCollection = require('../models/tags')
9
11
  String = require('string')
10
12
  config = require('../config')
11
13
 
@@ -73,6 +75,13 @@ module.exports = React.createClass
73
75
  cards.fetch success: ()-> cards.fetching = false
74
76
  document.title = config.title + '、ヒストリー'
75
77
  <List key='list' router={@props.router} cards={cards} />
78
+ when "tags"
79
+ console.log '[views/content] tags', @props
80
+ tags = new TagCollection()
81
+ tags.fetching = true
82
+ tags.fetch success: ()-> tags.fetching = false
83
+ document.title = config.title + '、タグ一覧'
84
+ <Tags tags={tags} />
76
85
  else
77
86
  null
78
87
  }
@@ -53,7 +53,7 @@ module.exports = React.createClass
53
53
  else
54
54
  @props.onRequestHide()
55
55
  @props.card.set 'title', @state.title
56
- location.hash = '/' + @state.title
56
+ location.hash = '/' + encodeURIComponent(@state.title)
57
57
  else
58
58
  @props.onRequestHide()
59
59
  @props.card = new CardModel()
@@ -0,0 +1,66 @@
1
+ # @cjsx React.DOM
2
+ $ = require('jquery')
3
+ React = require('react/addons')
4
+ Modal = require('react-bootstrap/lib/Modal')
5
+ Button = require('react-bootstrap/lib/Button')
6
+
7
+ module.exports = React.createClass
8
+ mixins: [React.addons.LinkedStateMixin]
9
+
10
+ displayName: 'EditTag'
11
+
12
+ getInitialState: ()->
13
+ updating: false
14
+ name: @props.tag.get('name')
15
+ errors: false
16
+ shaking: false
17
+
18
+ onChangeName: (event)->
19
+ @setState name: event.target.value
20
+
21
+ onClickOk: (event)->
22
+ event.preventDefault()
23
+ @setState updating: true
24
+ attributes = {new_name: @state.name}
25
+ @props.tag.save attributes,
26
+ success: ()=>
27
+ @props.tag.set 'name', @state.name
28
+ @props.onRequestHide()
29
+ error: (model, response, options)=>
30
+ @setState errors: response.responseJSON.tag.errors
31
+ @setState updating: false
32
+ @setState shaking: true
33
+ setTimeout (=> @setState shaking: false), 300
34
+
35
+ render: ->
36
+ <Modal className={"animated infinite shake" if @state.shaking} {...@props} bsStyle='default' title={<i className="glyphicon glyphicon-edit" />} animation={false}>
37
+ <div className='modal-body'>
38
+ {
39
+ if @state.errors
40
+ <div className="alert alert-danger" role="alert">
41
+ <ul>
42
+ {
43
+ for key, errors of @state.errors
44
+ for error in errors
45
+ <li>{key + ' ' + error}</li>
46
+ }
47
+ </ul>
48
+ </div>
49
+ }
50
+ <div className="form-group">
51
+ <label className="control-label">Name</label>
52
+ <input type="text" className="form-control" value={@state.name} onChange={@onChangeName} disabled={@state.updating} id="inputError1" />
53
+ </div>
54
+ <div className="form-group">
55
+ <button className="btn btn-default pull-right" onClick={@onClickOk} disabled={@state.updating}>
56
+ &nbsp;
57
+ OK
58
+ &nbsp;
59
+ {
60
+ if @state.updating
61
+ <i className='glyphicon glyphicon-refresh glyphicon-refresh-animate' />
62
+ }
63
+ </button>
64
+ </div>
65
+ </div>
66
+ </Modal>
@@ -81,6 +81,11 @@ module.exports = React.createClass
81
81
  </a>
82
82
  </li>
83
83
  }
84
+ <li>
85
+ <a href={"#/tags"}>
86
+ <i className="glyphicon glyphicon-tag" />
87
+ </a>
88
+ </li>
84
89
  <li>
85
90
  <a href={config.root_path + config.api_path + "/cards.xml?" + @queryParam({}, [])}>
86
91
  <i className="fa fa-rss" />
@@ -94,16 +99,20 @@ module.exports = React.createClass
94
99
  </ul>
95
100
  </div>
96
101
  <div className="col-sm-4">
97
- <a href="javascript:void(0)" className="center-block text-center">
98
- <span className="badge">
99
- {
100
- if @props.cards.pagination
101
- @props.cards.pagination.total_entries
102
- else
103
- <i className="glyphicon glyphicon-refresh glyphicon-refresh-animate" />
104
- }
105
- </span>
106
- </a>
102
+ <ul className="nav nav-pills nav-justified">
103
+ <li>
104
+ <a href="javascript:void(0)" className="center-block text-center">
105
+ <span className="badge">
106
+ {
107
+ if @props.cards.pagination
108
+ @props.cards.pagination.total_entries
109
+ else
110
+ <i className="glyphicon glyphicon-refresh glyphicon-refresh-animate" />
111
+ }
112
+ </span>
113
+ </a>
114
+ </li>
115
+ </ul>
107
116
  </div>
108
117
  <div className="col-sm-4">
109
118
  {
@@ -136,7 +145,7 @@ module.exports = React.createClass
136
145
  <div className="col-sm-12">
137
146
  <ul className="nav nav-pills">
138
147
  <li>
139
- <a href={"#/" + title + '?context=title'}>
148
+ <a href={"#/" + encodeURIComponent(title) + '?context=title'}>
140
149
  {
141
150
  if @props.card && @props.card.query.context == 'title'
142
151
  <strong>A to Z</strong>
@@ -146,7 +155,7 @@ module.exports = React.createClass
146
155
  </a>
147
156
  </li>
148
157
  <li>
149
- <a href={"#/" + title + '?context=updated_at'}>
158
+ <a href={"#/" + encodeURIComponent(title) + '?context=updated_at'}>
150
159
  {
151
160
  if @props.card && @props.card.query.context == 'updated_at'
152
161
  <strong>Latest</strong>
@@ -156,7 +165,7 @@ module.exports = React.createClass
156
165
  </a>
157
166
  </li>
158
167
  <li>
159
- <a href={"#/" + title + '?context=none'}>
168
+ <a href={"#/" + encodeURIComponent(title) + '?context=none'}>
160
169
  {
161
170
  if @props.card && @props.card.query.context == 'none'
162
171
  <strong>Detail</strong>
@@ -166,7 +175,7 @@ module.exports = React.createClass
166
175
  </a>
167
176
  </li>
168
177
  <li>
169
- <a href={"#/" + title + '/history'}>
178
+ <a href={"#/" + encodeURIComponent(title) + '/history'}>
170
179
  {
171
180
  if @props.cards.collectionName == 'CardHistories'
172
181
  <strong>History</strong>
@@ -0,0 +1,65 @@
1
+ # @cjsx React.DOM
2
+ $ = require('jquery')
3
+ Backbone = require('backbone')
4
+ React = require('react')
5
+ EditTag = require('./edit_tag')
6
+ ModalTrigger = require('react-bootstrap/lib/ModalTrigger')
7
+
8
+ module.exports = React.createClass
9
+ displayName: 'Tags'
10
+
11
+ componentDidMount: ->
12
+ console.log '[views/tags] component did mount'
13
+ @props.tags.on 'sync', @forceUpdate.bind(@, null)
14
+
15
+ componentWillReceiveProps: (nextProps)->
16
+ console.log '[views/tags] component will receive props'
17
+ nextProps.tags.on 'sync', @forceUpdate.bind(@, null)
18
+
19
+ render: ->
20
+ <div className="container carte-list">
21
+ <div className="row">
22
+ <div className="col-sm-12">
23
+ <ul className="nav nav-pills">
24
+ <li>
25
+ <a href="#/">
26
+ <i className="glyphicon glyphicon-arrow-left" />
27
+ </a>
28
+ </li>
29
+ </ul>
30
+ </div>
31
+ </div>
32
+
33
+ <div className="row">
34
+ {
35
+ if @props.tags.fetching
36
+ <div className="list-group col-sm-4">
37
+ <div className="list-group-item">
38
+ <i className="glyphicon glyphicon-refresh glyphicon-refresh-animate" />
39
+ </div>
40
+ </div>
41
+ else
42
+ @props.tags.map (tag)->
43
+ <div className="list-group col-sm-4">
44
+ <div className="list-group-item">
45
+ <i className="glyphicon glyphicon-tag" />
46
+ &nbsp;
47
+ {tag.get('name')}
48
+ &nbsp;
49
+ (
50
+ <a href={'#/?tags=' + encodeURIComponent(tag.get('name'))}>
51
+ {tag.get('count')}
52
+ </a>
53
+ )
54
+ <span className="pull-right tools">
55
+ <ModalTrigger modal={<EditTag tag={tag} />}>
56
+ <a href="javascript:void(0)">
57
+ <i className="glyphicon glyphicon-edit" />
58
+ </a>
59
+ </ModalTrigger>
60
+ </span>
61
+ </div>
62
+ </div>
63
+ }
64
+ </div>
65
+ </div>
@@ -135,6 +135,23 @@ module Carte
135
135
  {tags: Card.all_tags}.to_json
136
136
  end
137
137
 
138
+ put '/tags/:name.json' do
139
+ # TODO: existence and length validation
140
+ if json_data['new_name']
141
+ cards = Card.collection.where(tags: params[:name])
142
+ cards.update(
143
+ {'$push' => {tags: json_data['new_name']}},
144
+ {:multi => true}
145
+ )
146
+ cards.update(
147
+ {'$pull' => {tags: params[:name]}},
148
+ {:multi => true}
149
+ )
150
+ end
151
+ status 201
152
+ {}.to_json
153
+ end
154
+
138
155
  error(404) do
139
156
  {}.to_json
140
157
  end
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "carte-client",
3
3
  "description": "something like dictionary, wiki, or information card",
4
- "version": "1.0.8",
4
+ "version": "1.0.9",
5
5
  "main": "lib/carte.coffee",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carte-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.8
4
+ version: 1.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - tily
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-23 00:00:00.000000000 Z
11
+ date: 2015-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -267,6 +267,8 @@ files:
267
267
  - lib/carte/client/models/card_histories.coffee
268
268
  - lib/carte/client/models/card_history.coffee
269
269
  - lib/carte/client/models/cards.coffee
270
+ - lib/carte/client/models/tag.coffee
271
+ - lib/carte/client/models/tags.coffee
270
272
  - lib/carte/client/router.coffee
271
273
  - lib/carte/client/tasks.coffee
272
274
  - lib/carte/client/views/app.cjsx
@@ -274,12 +276,14 @@ files:
274
276
  - lib/carte/client/views/cards.cjsx
275
277
  - lib/carte/client/views/content.cjsx
276
278
  - lib/carte/client/views/edit.cjsx
279
+ - lib/carte/client/views/edit_tag.cjsx
277
280
  - lib/carte/client/views/footer.cjsx
278
281
  - lib/carte/client/views/header.cjsx
279
282
  - lib/carte/client/views/list.cjsx
280
283
  - lib/carte/client/views/message.cjsx
281
284
  - lib/carte/client/views/pagination.cjsx
282
285
  - lib/carte/client/views/slideshow.cjsx
286
+ - lib/carte/client/views/tags.cjsx
283
287
  - lib/carte/server.rb
284
288
  - lib/carte/server/models.rb
285
289
  - lib/carte/server/models/card.rb