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 +4 -4
- data/lib/carte/client/models/tag.coffee +9 -0
- data/lib/carte/client/models/tags.coffee +10 -0
- data/lib/carte/client/router.coffee +5 -0
- data/lib/carte/client/views/content.cjsx +9 -0
- data/lib/carte/client/views/edit.cjsx +1 -1
- data/lib/carte/client/views/edit_tag.cjsx +66 -0
- data/lib/carte/client/views/list.cjsx +23 -14
- data/lib/carte/client/views/tags.cjsx +65 -0
- data/lib/carte/server.rb +17 -0
- data/package.json +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd3f472fe4bb7d487fcdaed6f4ac9d6e4fcc55ae
|
4
|
+
data.tar.gz: c52db06dafe184f6a745ce5c678be0603b38e581
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
+
|
57
|
+
OK
|
58
|
+
|
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
|
-
<
|
98
|
-
<
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
+
|
47
|
+
{tag.get('name')}
|
48
|
+
|
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>
|
data/lib/carte/server.rb
CHANGED
@@ -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
|
data/package.json
CHANGED
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.
|
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-
|
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
|