Skip to content
This repository was archived by the owner on May 20, 2018. It is now read-only.

Commit 3eab2ad

Browse files
committed
Merge pull request #20 from levlaz/feature-tags
Feature tags
2 parents 2d03bca + e007ca1 commit 3eab2ad

File tree

12 files changed

+785
-3
lines changed

12 files changed

+785
-3
lines changed

app/main/forms.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class NoteForm(Form):
66
title = StringField('Title:', validators=[Required()])
77
body = TextAreaField('Dump Your Brain:', validators=[Required()])
88
body_html = TextAreaField()
9+
tags = StringField()
910
submit = SubmitField('Submit')
1011

1112
class ShareForm(Form):

app/main/views.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .. import db
77
from .forms import *
88
from ..email import send_email
9-
from ..models import User, Note
9+
from ..models import User, Note, Tag
1010

1111
@main.route('/', methods=['GET', 'POST'])
1212
def index():
@@ -15,6 +15,10 @@ def index():
1515
if form.validate_on_submit():
1616
note = Note(title=form.title.data,body=form.body.data, body_html=form.body_html.data,author=current_user._get_current_object())
1717
db.session.add(note)
18+
tags = []
19+
for tag in form.tags.data.split(','):
20+
tags.append(tag)
21+
note.str_tags = (tags)
1822
db.session.commit()
1923
return redirect(url_for('.index'))
2024
notes = Note.query.filter_by(author_id=current_user.id,is_deleted=False).order_by(Note.timestamp.desc()).all()
@@ -109,3 +113,9 @@ def share(id):
109113
flash('The note has been shared with ' + recipient_name + '.')
110114
return redirect(url_for('.index'))
111115
return render_template('share_note.html', form = form, notes=[note])
116+
117+
@main.route('/tag/<name>')
118+
@login_required
119+
def tag(name):
120+
tag = Tag.query.filter_by(tag=name).first()
121+
return render_template('tag.html', notes=tag.notes, tag=name)

app/models.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@
1414
def load_user(user_id):
1515
return User.query.get(int(user_id))
1616

17+
# Association Tables
18+
note_tag = db.Table(
19+
'note_tag',
20+
db.Column(
21+
'note_id',
22+
db.Integer,
23+
db.ForeignKey('notes.id', ondelete="CASCADE")),
24+
db.Column(
25+
'tag_id',
26+
db.Integer,
27+
db.ForeignKey('tags.id', ondelete="CASCADE")))
28+
1729
class Role(db.Model):
1830
__tablename__ = 'roles'
1931
id = db.Column(db.Integer, primary_key=True)
@@ -133,6 +145,28 @@ class Note(db.Model):
133145
section_id = db.Column(db.Integer, db.ForeignKey('sections.id'))
134146
is_deleted = db.Column(db.Boolean, default=False)
135147

148+
tags = db.relationship("Tag", secondary=note_tag, backref="Note")
149+
150+
def _find_or_create_tag(self, tag):
151+
q = Tag.query.filter_by(tag=tag)
152+
t = q.first()
153+
if not (t):
154+
t = Tag(tag=tag.strip())
155+
return t
156+
157+
def _get_tags(self):
158+
return [x.tag for x in self.tags]
159+
160+
def _set_tags(self, value):
161+
while self.tags:
162+
del self.tags[0]
163+
for tag in value:
164+
self.tags.append(self._find_or_create_tag(tag))
165+
166+
str_tags = property(_get_tags,
167+
_set_tags,
168+
"Property str_tags is a simple wrapper for the tags relationship")
169+
136170
class Notebook(db.Model):
137171
__tablename__ = 'notebooks'
138172
id = db.Column(db.Integer, primary_key=True)
@@ -147,3 +181,13 @@ class Section(db.Model):
147181
notebook_id = db.Column(db.Integer, db.ForeignKey('notebooks.id'))
148182

149183
notes = db.relationship('Note', backref='section', lazy='dynamic')
184+
185+
class Tag(db.Model):
186+
__tablename__ = 'tags'
187+
id = db.Column(db.Integer, primary_key=True)
188+
tag = db.Column(db.String(200))
189+
190+
notes = db.relationship("Note", secondary=note_tag, backref="Tag")
191+
192+
def _get_notes(self):
193+
return [x.title for x in self.notes]
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
.bootstrap-tagsinput {
2+
background-color: #fff;
3+
border: 1px solid #ccc;
4+
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
5+
display: inline-block;
6+
padding: 4px 6px;
7+
color: #555;
8+
vertical-align: middle;
9+
border-radius: 4px;
10+
max-width: 100%;
11+
line-height: 22px;
12+
cursor: text;
13+
margin-bottom: 5px;
14+
}
15+
.bootstrap-tagsinput input {
16+
border: none;
17+
box-shadow: none;
18+
outline: none;
19+
background-color: transparent;
20+
padding: 0 6px;
21+
margin: 0;
22+
width: auto;
23+
max-width: inherit;
24+
}
25+
.bootstrap-tagsinput.form-control input::-moz-placeholder {
26+
color: #777;
27+
opacity: 1;
28+
}
29+
.bootstrap-tagsinput.form-control input:-ms-input-placeholder {
30+
color: #777;
31+
}
32+
.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {
33+
color: #777;
34+
}
35+
.bootstrap-tagsinput input:focus {
36+
border: none;
37+
box-shadow: none;
38+
}
39+
.bootstrap-tagsinput .tag {
40+
margin-right: 2px;
41+
color: white;
42+
}
43+
.bootstrap-tagsinput .tag [data-role="remove"] {
44+
margin-left: 8px;
45+
cursor: pointer;
46+
}
47+
.bootstrap-tagsinput .tag [data-role="remove"]:after {
48+
content: "x";
49+
padding: 0px 2px;
50+
}
51+
.bootstrap-tagsinput .tag [data-role="remove"]:hover {
52+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
53+
}
54+
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
55+
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
56+
}

app/static/css/style.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ div.pagination {
6868
margin: 0px;
6969
}
7070

71+
.tags {
72+
font-weight: bold;
73+
float: left;
74+
padding-right: 5px;
75+
}
76+
7177
.note-body h1 {
7278
font-size: 140%;
7379
}

0 commit comments

Comments
 (0)