-
-
Save coleifer/632d3c9aa6b2ea519384 to your computer and use it in GitHub Desktop.
Note-taking app
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
from flask import Flask | |
from micawber import bootstrap_basic | |
from peewee import SqliteDatabase | |
APP_ROOT = os.path.dirname(os.path.realpath(__file__)) | |
DATABASE = os.path.join(APP_ROOT, 'notes.db') | |
DEBUG = False | |
app = Flask(__name__) | |
app.config.from_object(__name__) | |
db = SqliteDatabase(app.config['DATABASE'], threadlocals=True) | |
oembed = bootstrap_basic() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from app import app | |
from models import Note | |
import views | |
if __name__ == '__main__': | |
Note.create_table(True) | |
app.run(debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import datetime | |
from flask import Markup | |
from markdown import markdown | |
from micawber import parse_html | |
from peewee import * | |
from app import db, oembed | |
class Note(Model): | |
content = TextField() | |
timestamp = DateTimeField(default=datetime.datetime.now) | |
archived = BooleanField(default=False) | |
class Meta: | |
database = db | |
def html(self): | |
html = parse_html( | |
markdown(self.content), | |
oembed, | |
maxwidth=300, | |
urlize_all=True) | |
return Markup(html) | |
@classmethod | |
def public(cls): | |
return (Note | |
.select() | |
.where(Note.archived == False) | |
.order_by(Note.timestamp.desc())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Notes = window.Notes || {}; | |
(function(exports, $) { | |
function Editor() { | |
this.form = $('form#note-form'); | |
this.editor = $('textarea#content'); | |
this.container = $('ul.notes'); | |
this.initialize(); | |
} | |
Editor.prototype.initialize = function() { | |
this.setupMasonry(); | |
this.setupNotes(); | |
this.setupForm(); | |
this.editor.focus(); | |
} | |
Editor.prototype.setupMasonry = function() { | |
var self = this; | |
imagesLoaded(this.container, function() { | |
self.container.masonry({'itemSelector': '.note'}); | |
}); | |
} | |
Editor.prototype.setupNotes = function() { | |
var self = this; | |
$('a.archive-note').on('click', this.archiveNote); | |
} | |
Editor.prototype.archiveNote = function(e) { | |
e.preventDefault(); | |
var elem = $(this); | |
var panel = elem.parents('.panel'); | |
var self = this; | |
$.post(elem.attr('href'), function(data) { | |
if (data.success) { | |
panel.remove(); | |
$('ul.notes').masonry(); | |
} | |
}); | |
} | |
Editor.prototype.setupForm = function() { | |
var self = this; | |
this.editor.on('keydown', function(e) { | |
if (e.ctrlKey && e.keyCode == 13) { | |
self.form.submit(); | |
} | |
}); | |
this.form.submit(function(e) { | |
e.preventDefault(); | |
self.addNote(); | |
}); | |
this.addMarkdownHelpers(); | |
} | |
Editor.prototype.addNote = function() { | |
var self = this; | |
this.editor.css('color', '#464545'); | |
$.post(this.form.attr('target'), this.form.serialize(), function(data) { | |
if (data.success) { | |
self.editor.val('').focus(); | |
listElem = $(data.note); | |
listElem.find('a.archive-note').on('click', self.archiveNote); | |
self.container.prepend(listElem); | |
self.container.masonry('prepended', listElem); | |
} else { | |
self.editor.css('color', '#dd1111'); | |
} | |
}); | |
} | |
Editor.prototype.addMarkdownHelpers = function() { | |
var self = this; | |
this.addHelper('indent-left', function(line) { | |
return ' ' + line; | |
}); | |
this.addHelper('indent-right', function(line) { | |
return line.substring(4); | |
}); | |
this.addHelper('list', function(line) { | |
return '* ' + line; | |
}); | |
this.addHelper('bold', function(line) { | |
return '**' + line + '**'; | |
}); | |
this.addHelper('italic', function(line) { | |
return '*' + line + '*'; | |
}); | |
this.addHelper('font', null, function() { | |
self.focus().select(); | |
}); | |
} | |
Editor.prototype.addHelper = function(iconClass, lineHandler, callBack) { | |
var link = $('<a>', {'class': 'btn btn-xs'}), | |
icon = $('<span>', {'class': 'glyphicon glyphicon-' + iconClass}), | |
self = this; | |
if (!callBack) { | |
callBack = function() { | |
self.modifySelection(lineHandler); | |
} | |
} | |
link.on('click', function(e) { | |
e.preventDefault(); | |
callBack(); | |
}); | |
link.append(icon); | |
this.editor.before(link); | |
} | |
Editor.prototype.modifySelection = function(lineHandler) { | |
var selection = this.getSelectedText(); | |
if (!selection) return; | |
var lines = selection.split('\n'), | |
result = []; | |
for (var i = 0; i < lines.length; i++) { | |
result.push(lineHandler(lines[i])); | |
} | |
this.editor.val( | |
this.editor.val().split(selection).join(result.join('\n')) | |
); | |
} | |
Editor.prototype.getSelectedText = function() { | |
var textAreaDOM = this.editor[0]; | |
return this.editor.val().substring( | |
textAreaDOM.selectionStart, | |
textAreaDOM.selectionEnd); | |
} | |
exports.Editor = Editor; | |
})(Notes, jQuery); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<title>Notes</title> | |
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet"> | |
<link href="{{ url_for('static', filename='css/site.css') }}" rel="stylesheet"> | |
<script src="{{ url_for('static', filename='js/jquery-1.11.0.min.js') }}"></script> | |
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script> | |
<script src="{{ url_for('static', filename='js/imagesloaded.pkgd.min.js') }}"></script> | |
<script src="{{ url_for('static', filename='js/masonry.pkgd.min.js') }}"></script> | |
<script src="{{ url_for('static', filename='js/notes.js') }}"></script> | |
<script type="text/javascript"> | |
$(function() { | |
new Notes.Editor(); | |
}); | |
</script> | |
</head> | |
<body> | |
<div class="container content"> | |
<div class="page-header"> | |
<h1>Notes</h1> | |
</div> | |
<form action="." class="form" id="note-form" method="post"> | |
<button class="btn btn-primary btn-xs" type="submit"> | |
<span class="glyphicon glyphicon-plus"></span> Add Note | |
</button> | |
<textarea class="form-control" id="content" name="content"></textarea> | |
</form> | |
<ul class="list-unstyled notes"> | |
{% for note in notes %} | |
{% include "note.html" %} | |
{% endfor %} | |
</ul> | |
<div style="clear:both;"></div> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<li class="note col-xs-12 col-sm-6 col-lg-4"> | |
<div class="panel panel-primary"> | |
<div class="panel-heading"> | |
{{ note.timestamp.strftime('%b %d, %Y %I:%M%p').lower() }} | |
<a | |
class="btn btn-danger btn-xs archive-note pull-right" | |
data-note="{{ note.id }}" | |
href="{{ url_for('archive_note', pk=note.id) }}">×</a> | |
</div> | |
<div class="panel-body"> | |
{{ note.html() }} | |
</div> | |
</div> | |
</li> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from flask import abort, jsonify, render_template, request | |
from app import app | |
from models import Note | |
def get_page(): | |
page = request.args.get('page') | |
if not page or not page.isdigit(): | |
return 1 | |
return min(int(page), 1) | |
@app.route('/', methods=['GET', 'POST']) | |
def homepage(): | |
if request.method == 'POST': | |
if request.form.get('content'): | |
note = Note.create(content=request.form['content']) | |
rendered = render_template('note.html', note=note) | |
return jsonify({'note': rendered, 'success': True}) | |
return jsonify({'success': False}) | |
notes = Note.public().paginate(get_page(), 50) | |
return render_template('homepage.html', notes=notes) | |
@app.route('/archive/<int:pk>/', methods=['POST']) | |
def archive_note(pk): | |
try: | |
note = Note.get(Note.id == pk) | |
except Note.DoesNotExist: | |
abort(404) | |
note.archived = True | |
note.save() | |
return jsonify({'success': True}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment