carte-server 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/carte.gemspec +1 -0
- data/lib/carte/client/views/card.cjsx +10 -3
- data/lib/carte/client/views/edit.cjsx +11 -3
- data/lib/carte/client/views/list.cjsx +10 -0
- data/lib/carte/server.rb +14 -4
- data/lib/carte/server/models/card.rb +5 -2
- data/lib/carte/server/version.rb +1 -1
- data/lib/carte/server/views/index.haml +57 -0
- data/package.json +2 -1
- data/spec/server_spec.rb +37 -0
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05fe3f4e42f3d067dbac24787cab7c81c131d10d
|
4
|
+
data.tar.gz: d6d15321dddf1b368e836d3a1a65762c03c7e85f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63aa6e882126fd60d9d878326af349a847219bcfd0dd554dbf80e234648b7df3181b7bf31dc3546879e041f0444cb9b2a274a5730c6cd37318a86ebe3c7bdfb5
|
7
|
+
data.tar.gz: ecd5f98f70dd2f6bb6e39251208abe70b96b39222022dde21754403b257d2f1e1e8230213089c63b30c2bf561bdf663e576ad93973fbbce96637b97e045932c2
|
data/carte.gemspec
CHANGED
@@ -30,7 +30,7 @@ module.exports = React.createClass
|
|
30
30
|
console.log 'Card: render'
|
31
31
|
<div className='col-sm-4 col-xs-12 list-group' style={marginBottom:'0px',padding:"5px"} onMouseOver={@onMouseOver} onMouseLeave={@onMouseLeave}>
|
32
32
|
<div className='list-group-item' style={height:'220px'}>
|
33
|
-
<div>
|
33
|
+
<div style={marginBottom:'10px'}>
|
34
34
|
{
|
35
35
|
if @props.card.get('focused')
|
36
36
|
<i className='glyphicon glyphicon-star' style={marginRight:'5px'} />
|
@@ -51,8 +51,15 @@ module.exports = React.createClass
|
|
51
51
|
</a>
|
52
52
|
</span>
|
53
53
|
</div>
|
54
|
-
<div style={overflow:'hidden',width:'100%',height:'
|
55
|
-
<
|
54
|
+
<div style={overflow:'hidden',width:'100%',height:'75%',wordWrap:'break-word'}>
|
55
|
+
<div dangerouslySetInnerHTML={__html: markdownIt.render @props.card.get('content')} />
|
56
|
+
</div>
|
57
|
+
<div style={{visibility: if @isSafariOrUiWebView || @state.showTools then 'visible' else 'hidden'}}>
|
58
|
+
{
|
59
|
+
if @props.card.get("tags")
|
60
|
+
@props.card.get("tags").map (tag)->
|
61
|
+
<span className="pull-right tools"> <a href={"/#/?tags=" + tag}><i className="glyphicon glyphicon-tag" /> {tag}</a></span>
|
62
|
+
}
|
56
63
|
</div>
|
57
64
|
</div>
|
58
65
|
</div>
|
@@ -1,16 +1,20 @@
|
|
1
1
|
# @cjsx React.DOM
|
2
2
|
$ = require('jquery')
|
3
|
-
React = require('react')
|
3
|
+
React = require('react/addons')
|
4
4
|
Modal = require('react-bootstrap/lib/Modal')
|
5
5
|
Button = require('react-bootstrap/lib/Button')
|
6
|
+
TagsInput = require('react-tagsinput')
|
6
7
|
|
7
8
|
module.exports = React.createClass
|
9
|
+
mixins: [React.addons.LinkedStateMixin]
|
10
|
+
|
8
11
|
displayName: 'Edit'
|
9
12
|
|
10
13
|
getInitialState: ()->
|
11
14
|
updating: false
|
12
15
|
title: @props.card.get('title')
|
13
16
|
content: @props.card.get('content')
|
17
|
+
tags: @props.card.get('tags') || []
|
14
18
|
errors: false
|
15
19
|
|
16
20
|
onChangeTitle: ->
|
@@ -23,9 +27,9 @@ module.exports = React.createClass
|
|
23
27
|
event.preventDefault()
|
24
28
|
@setState updating: true
|
25
29
|
if @props.card.isNew()
|
26
|
-
attributes = {title: @state.title, content: @state.content}
|
30
|
+
attributes = {title: @state.title, content: @state.content, tags: @state.tags}
|
27
31
|
else
|
28
|
-
attributes = {new_title: @state.title, content: @state.content}
|
32
|
+
attributes = {new_title: @state.title, content: @state.content, tags: @state.tags}
|
29
33
|
@props.card.save attributes,
|
30
34
|
success: ()=>
|
31
35
|
@setState updating: false
|
@@ -61,6 +65,10 @@ module.exports = React.createClass
|
|
61
65
|
<label class="control-label">Content</label>
|
62
66
|
<textarea rows="10" className="form-control" value={@state.content} onChange={@onChangeContent} disabled={@state.updating} />
|
63
67
|
</div>
|
68
|
+
<div className="form-group">
|
69
|
+
<label class="control-label">Tags</label>
|
70
|
+
<TagsInput ref='tags' valueLink={this.linkState('tags')} />
|
71
|
+
</div>
|
64
72
|
<div className="form-group" style={{paddingBottom:'17px'}}>
|
65
73
|
<button className="btn btn-default pull-right" onClick={@onClickOk} disabled={@state.updating}>
|
66
74
|
|
@@ -38,6 +38,11 @@ module.exports = React.createClass
|
|
38
38
|
query = $.extend query, {page: page}
|
39
39
|
$.param(query)
|
40
40
|
|
41
|
+
tagParam: (tag)->
|
42
|
+
query = $.extend {}, @props.cards.query
|
43
|
+
query = $.extend query, {tags: tag}
|
44
|
+
$.param(query)
|
45
|
+
|
41
46
|
render: ->
|
42
47
|
console.log 'render', @props.cards.query
|
43
48
|
<div className="container" style={{paddingLeft:"5px",paddingRight:"5px"}}>
|
@@ -48,6 +53,11 @@ module.exports = React.createClass
|
|
48
53
|
<li><a href={"/#/?" + @atozParam()} style={{padding:'6px 12px',fontWeight: if @props.cards.query.sort == 'title' and @props.cards.query.order != 'random' then 'bold' else 'normal'}}>A to Z</a></li>
|
49
54
|
<li><a href={"/#/?" + @latestParam()} style={{padding:'6px 12px',fontWeight: if @props.cards.query.sort == 'updated_at' and @props.cards.query.order != 'random' then 'bold' else 'normal'}}>Latest</a></li>
|
50
55
|
<li><a href={"/#/?" + @randomParam()} style={{padding:'6px 12px',fontWeight: if @props.cards.query.order == 'random' then 'bold' else 'normal'}}>Random</a></li>
|
56
|
+
{
|
57
|
+
if @props.cards.query.tags
|
58
|
+
@props.cards.query.tags.split(',').map (tag)->
|
59
|
+
<li><a href={"/#/?" + @tagParam()} style={padding:'6px 12px'}><i className="glyphicon glyphicon-tag" /> {tag}</a></li>
|
60
|
+
}
|
51
61
|
</ul>
|
52
62
|
</div>
|
53
63
|
<div className="col-sm-6" style={{padding:"0px"}}>
|
data/lib/carte/server.rb
CHANGED
@@ -3,6 +3,7 @@ require 'sinatra/namespace'
|
|
3
3
|
require 'mongoid'
|
4
4
|
require 'mongoid_auto_increment_id'
|
5
5
|
require 'will_paginate_mongoid'
|
6
|
+
require 'mongoid-simple-tags'
|
6
7
|
require 'carte/server/models'
|
7
8
|
|
8
9
|
module Carte
|
@@ -33,6 +34,10 @@ module Carte
|
|
33
34
|
if title = params[:title]
|
34
35
|
cards = cards.any_of({title: /#{title}/})
|
35
36
|
end
|
37
|
+
if params[:tags]
|
38
|
+
tags = params[:tags].split(',')
|
39
|
+
cards = cards.tagged_with_all(tags)
|
40
|
+
end
|
36
41
|
if content = params[:content]
|
37
42
|
cards = cards.any_of({content: /#{content}/})
|
38
43
|
end
|
@@ -60,18 +65,18 @@ module Carte
|
|
60
65
|
current_page = cards.current_page.to_i
|
61
66
|
total_pages = cards.total_pages
|
62
67
|
end
|
63
|
-
cards = cards.map {|card| {id: card.id, title: card.title, content: card.content, version: card.version}}
|
68
|
+
cards = cards.map {|card| {id: card.id, title: card.title, content: card.content, version: card.version, tags: card.tags}}
|
64
69
|
{cards: cards, page: {current: current_page, total: total_pages}}.to_json
|
65
70
|
end
|
66
71
|
|
67
72
|
get '/cards/:title.json' do
|
68
73
|
card = Card.where(title: params[:title]).first
|
69
74
|
halt 404 if card.nil?
|
70
|
-
{card: {id: card.id, title: card.title, content: card.content, version: card.version, lefts: card.lefts(4), rights: card.rights(4)}}.to_json
|
75
|
+
{card: {id: card.id, title: card.title, content: card.content, version: card.version, tags: card.tags, lefts: card.lefts(4), rights: card.rights(4)}}.to_json
|
71
76
|
end
|
72
77
|
|
73
78
|
post '/cards.json' do
|
74
|
-
card = Card.new(json_data)
|
79
|
+
card = Card.new(json_data.slice('title', 'content', 'tags'))
|
75
80
|
if card.save
|
76
81
|
status 201
|
77
82
|
{card: {id: card.id}}.to_json
|
@@ -85,7 +90,8 @@ module Carte
|
|
85
90
|
card = Card.where(title: params[:title]).first
|
86
91
|
halt 404 if card.nil?
|
87
92
|
card.histories.create!
|
88
|
-
|
93
|
+
p json_data.slice('new_title', 'content', 'tags').compact
|
94
|
+
if card.update_attributes(json_data.slice('new_title', 'content', 'tags').compact)
|
89
95
|
status 201
|
90
96
|
{}.to_json
|
91
97
|
else
|
@@ -106,6 +112,10 @@ module Carte
|
|
106
112
|
{history: card.histories}.to_json
|
107
113
|
end
|
108
114
|
|
115
|
+
get '/tags.json' do
|
116
|
+
{tags: Card.all_tags}.to_json
|
117
|
+
end
|
118
|
+
|
109
119
|
error(404) do
|
110
120
|
{}.to_json
|
111
121
|
end
|
@@ -5,6 +5,7 @@ module Carte
|
|
5
5
|
include Mongoid::Document
|
6
6
|
include Mongoid::Timestamps
|
7
7
|
include Mongoid::Attributes::Dynamic
|
8
|
+
include Mongoid::Document::Taggable
|
8
9
|
|
9
10
|
field :title, type: String
|
10
11
|
field :new_title, type: String
|
@@ -29,8 +30,10 @@ module Carte
|
|
29
30
|
end
|
30
31
|
|
31
32
|
before_validation(on: :update) do
|
32
|
-
|
33
|
-
|
33
|
+
if self.new_title
|
34
|
+
self.title = self.new_title
|
35
|
+
self.new_title = nil
|
36
|
+
end
|
34
37
|
end
|
35
38
|
|
36
39
|
def self.sample(size=1)
|
data/lib/carte/server/version.rb
CHANGED
@@ -38,5 +38,62 @@
|
|
38
38
|
from { transform: scale(1) rotate(0deg);}
|
39
39
|
to { transform: scale(1) rotate(360deg);}
|
40
40
|
}
|
41
|
+
|
42
|
+
/* https://github.com/olahol/react-tagsinput/blob/master/react-tagsinput.css */
|
43
|
+
.react-tagsinput {
|
44
|
+
border: 1px solid #ccc;
|
45
|
+
background: #fff;
|
46
|
+
padding: 10px;
|
47
|
+
overflow-y: auto;
|
48
|
+
border-radius: 3px;
|
49
|
+
}
|
50
|
+
|
51
|
+
.react-tagsinput-tag {
|
52
|
+
display: block;
|
53
|
+
/*border: 1px solid #a5d24a;*/
|
54
|
+
/*background: #cde69c;*/
|
55
|
+
/*color: #638421;*/
|
56
|
+
/*font-size: 12px;*/
|
57
|
+
/*font-family: 'Helvetica Neue', 'Arial', sans-serif;*/
|
58
|
+
float: left;
|
59
|
+
/*padding: 5px;*/
|
60
|
+
margin-right: 5px;
|
61
|
+
/*margin-bottom: 5px;*/
|
62
|
+
text-decoration: none;
|
63
|
+
border-radius: 2px;
|
64
|
+
}
|
65
|
+
|
66
|
+
.react-tagsinput-invalid {
|
67
|
+
background: #FBD8DB !important;
|
68
|
+
color: #90111A !important;
|
69
|
+
}
|
70
|
+
|
71
|
+
.react-tagsinput-validating {
|
72
|
+
/* background: #FFFACD !important; */
|
73
|
+
}
|
74
|
+
|
75
|
+
.react-tagsinput-remove {
|
76
|
+
font-weight: bold;
|
77
|
+
/* color: #638421; */
|
78
|
+
text-decoration: none;
|
79
|
+
font-size: 11px;
|
80
|
+
cursor: pointer;
|
81
|
+
}
|
82
|
+
|
83
|
+
.react-tagsinput-remove:before {
|
84
|
+
/* content: " x"; */
|
85
|
+
}
|
86
|
+
|
87
|
+
.react-tagsinput-input {
|
88
|
+
background: transparent;
|
89
|
+
/* color: #777; */
|
90
|
+
border: 0;
|
91
|
+
/* font-size: 13px; */
|
92
|
+
/* font-family: 'Helvetica Neue', 'Arial', sans-serif; */
|
93
|
+
/*padding: 5px;*/
|
94
|
+
margin: 0;
|
95
|
+
width: 80px;
|
96
|
+
outline: none;
|
97
|
+
}
|
41
98
|
%body
|
42
99
|
#app
|
data/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "carte-client",
|
3
3
|
"description": "something like dictionary, wiki, or information card",
|
4
|
-
"version": "0.0.
|
4
|
+
"version": "0.0.6",
|
5
5
|
"main": "lib/carte.coffee",
|
6
6
|
"scripts": {
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
@@ -34,6 +34,7 @@
|
|
34
34
|
"markdown-it": "^4.2.0",
|
35
35
|
"react": "^0.13.2",
|
36
36
|
"react-bootstrap": "^0.21.0",
|
37
|
+
"react-tagsinput": "^1.3.2",
|
37
38
|
"vinyl-source-stream": "^1.1.0",
|
38
39
|
"watchify": "^3.1.2"
|
39
40
|
}
|
data/spec/server_spec.rb
CHANGED
@@ -171,4 +171,41 @@ describe 'API' do
|
|
171
171
|
end
|
172
172
|
end
|
173
173
|
end
|
174
|
+
|
175
|
+
context 'Tags' do
|
176
|
+
it 'can create and get a card with tags' do
|
177
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1', tags: %w(tag1 tag2 tag3)}.to_json)
|
178
|
+
expect(response.code).to eq(201)
|
179
|
+
response = client.get("/cards/card1.json")
|
180
|
+
expect(response['card']['tags']).to eq %w(tag1 tag2 tag3)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'can update card with tags' do
|
184
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1', tags: %w(tag1 tag2 tag3)}.to_json)
|
185
|
+
response = client.put("/cards/card1.json", body: {tags: %w(tag4 tag5 tag6)}.to_json)
|
186
|
+
expect(response.code).to eq(201)
|
187
|
+
response = client.get("/cards/card1.json")
|
188
|
+
expect(response['card']['tags']).to eq %w(tag4 tag5 tag6)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'can list cards with tags' do
|
192
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1', tags: %w(tag1 tag2 tag3)}.to_json)
|
193
|
+
response = client.get("/cards.json", query: {name: '^cards1$'})
|
194
|
+
expect(response['cards'].first['tags']).to eq %w(tag1 tag2 tag3)
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'can search cards by tags' do
|
198
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1', tags: %w(tag1 tag2 tag3)}.to_json)
|
199
|
+
response = client.get("/cards.json", query: {tags: 'tag1,tag2,tag3'})
|
200
|
+
expect(response['cards'].size).to eq(1)
|
201
|
+
expect(response['cards'].first['tags']).to eq %w(tag1 tag2 tag3)
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'can get tags' do
|
205
|
+
response = client.post('/cards.json', body: {title: 'card1', content: 'content1', tags: %w(tag1 tag2 tag3)}.to_json)
|
206
|
+
response = client.post('/cards.json', body: {title: 'card2', content: 'content2', tags: %w(tag4 tag5 tag6)}.to_json)
|
207
|
+
response = client.get("/tags.json")
|
208
|
+
expect(response['tags'].size).to eq(6)
|
209
|
+
end
|
210
|
+
end
|
174
211
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carte-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tily
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - '>='
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: mongoid-simple-tags
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - '>='
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :runtime
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - '>='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
181
195
|
description: something like dictionary, wiki, or information card
|
182
196
|
email:
|
183
197
|
- tidnlyam@gmail.com
|