From c57494ae405ffbdd8ec45f74ef04ea85895f1bf7 Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Fri, 15 Mar 2019 18:45:47 +0100 Subject: Port application to flask --- .gitignore | 3 +- db.py | 56 --------- pastepy.py | 292 ------------------------------------------- pastepy/__init__.py | 8 ++ pastepy/db.py | 68 ++++++++++ pastepy/pastepy.py | 169 +++++++++++++++++++++++++ pastepy/static/edit.js | 83 ++++++++++++ pastepy/static/paste.css | 23 ++++ pastepy/static/view.js | 26 ++++ pastepy/templates/base.html | 20 +++ pastepy/templates/full.html | 18 +++ pastepy/templates/paste.html | 34 +++++ pastepy/templates/view.html | 28 +++++ static/edit.js | 83 ------------ static/paste.css | 23 ---- static/view.js | 5 - templates/base.html | 20 --- templates/full.html | 18 --- templates/message.html | 5 - templates/paste.html | 34 ----- templates/view.html | 28 ----- 21 files changed, 479 insertions(+), 565 deletions(-) delete mode 100644 db.py delete mode 100644 pastepy.py create mode 100644 pastepy/__init__.py create mode 100644 pastepy/db.py create mode 100644 pastepy/pastepy.py create mode 100644 pastepy/static/edit.js create mode 100644 pastepy/static/paste.css create mode 100644 pastepy/static/view.js create mode 100644 pastepy/templates/base.html create mode 100644 pastepy/templates/full.html create mode 100644 pastepy/templates/paste.html create mode 100644 pastepy/templates/view.html delete mode 100644 static/edit.js delete mode 100644 static/paste.css delete mode 100644 static/view.js delete mode 100644 templates/base.html delete mode 100644 templates/full.html delete mode 100644 templates/message.html delete mode 100644 templates/paste.html delete mode 100644 templates/view.html diff --git a/.gitignore b/.gitignore index eb0a79c..ce796f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .*.swp *.pyc +__pycache__ /settings.py /db -templates/*.py +*.cfg diff --git a/db.py b/db.py deleted file mode 100644 index 8b2591d..0000000 --- a/db.py +++ /dev/null @@ -1,56 +0,0 @@ -import settings - -from sqlalchemy import create_engine, Column, Integer, String, DateTime, Text, Index, ForeignKey -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker, relation, backref -from sqlalchemy.orm.exc import NoResultFound - -engine = create_engine(settings.db_path) - -Base = declarative_base(bind = engine) - -class Paste(Base): - __tablename__ = 'paste' - - id = Column(Integer, primary_key = True) - hash = Column(String, unique = True, index = True) - nick = Column(String) - date = Column(DateTime, nullable = False) - syntax = Column(String) - title = Column(String) - text = Column(Text, nullable = False) - ip = Column(String) - - def __init__(self, hash, nick, date, syntax, title, text, ip=None): - self.nick = nick - self.hash = hash - self.date = date - self.syntax = syntax - self.title = title - self.text = text - self.ip = ip - - def __repr__(self): - return '' % (self.id, self.hash, self.nick, self.date.ctime(), self.title) - -class Cache(Base): - __tablename__ = 'cache' - - id = Column(Integer, primary_key = True) - paste_hash = Column(String, ForeignKey('paste.hash'), index = True) - paste = relation(Paste, primaryjoin = paste_hash == Paste.hash, lazy = False) - syntax_name = Column(String) - text = Column(Text, nullable = False) - - def __init__(self, hash, syntax_name, text): - self.paste_hash = hash - self.syntax_name = syntax_name - self.text = text - - def __repr__(self): - return '' % (self.id, self.paste_hash) - -Base.metadata.create_all() -Session = sessionmaker(bind = engine, autoflush = True, autocommit = False) - -# vim: noet ts=4 diff --git a/pastepy.py b/pastepy.py deleted file mode 100644 index 96d3f40..0000000 --- a/pastepy.py +++ /dev/null @@ -1,292 +0,0 @@ -import cgi -try: - from http.cookies import SimpleCookie -except ImportError: - from Cookie import SimpleCookie -import datetime -import db -import mimetypes -import os -import random - -import settings - -import jinja2 -try: - import markdown - has_markdown = True -except ImportError: - has_markdown = False -import pygments -from pygments import highlight -from pygments.lexers import get_all_lexers, get_lexer_by_name -from pygments.formatters import HtmlFormatter -import six - -base62_alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' - -def b2t(s): - '''Convert binary types to text types.''' - if isinstance(s, six.binary_type): - return s.decode('utf-8') - return s - -def t2b(s): - '''Convert text types to binary types.''' - if isinstance(s, six.text_type): - return s.encode('utf-8') - return s - -class PasteError(Exception): pass -class UnknownSyntaxError(PasteError): pass - -class CustomHtmlFormatter(HtmlFormatter): - def wrap(self, source, outfile): - yield 0, '
'
-		line = 1
-		for i, t in source:
-			yield i, '%s' % (line, t)
-			line += 1
-		yield 0, '
' - -class Paste(object): - def __init__(self): - lexers = dict([(x[0], x[1][0]) for x in get_all_lexers()]) - self.lexers = [] - removed = [] - for cat, ls in settings.categories: - for l in ls: - removed.append(l) - self.lexers.append((cat, [(x, lexers[x]) for x in ls])) - for l in removed: - try: - del lexers[l] - except KeyError: - pass - rendered = [] - if has_markdown: - rendered.append(('Rendered markdown', 'md-render')) - if len(rendered): - self.lexers.append(('Rendered', rendered)) - self.lexers.append(('Others' if settings.categories else 'Syntax', sorted(lexers.items(), key = lambda l: l[0].lower()))) - self.formatter = CustomHtmlFormatter(linenos = 'table', lineanchors = 'line', anchorlinenos = True) - - random.seed() - - self.template_env = jinja2.Environment(loader = jinja2.FileSystemLoader('templates')) - - def render_template(self, name, args): - template = self.template_env.get_template(name) - data = template.render(**args).encode('utf-8') - self.start_response('200 OK', [('Content-Type', 'text/html; charset=UTF-8'), ('Content-Length', str(len(data)))]) - return [data] - - def message(self, msg, title = 'Message'): - return self.render_template('message.html', { - 'title': '%s – %s' % (settings.pastebin_name, title), - 'header': title, - 'text': msg, - }) - - def paste(self): - c = SimpleCookie(self.environ['HTTP_COOKIE'] if 'HTTP_COOKIE' in self.environ else None) - if self.environ['REQUEST_METHOD'] == 'POST': - mp = cgi.FieldStorage(fp = self.environ['wsgi.input'], environ = self.environ, keep_blank_values = True) - if mp['type'].value == 'Preview': - return self.preview(mp) - elif mp['type'].value == 'Paste': - return self.add_paste(mp) - else: - return self.message('Invalid type "%s".' % mp['type'].value, 'Error') - return self.render_template('paste.html', { - 'title': settings.pastebin_name, - 'header': settings.pastebin_name, - 'lexers': self.lexers, - 'nick': b2t(c['nick'].value if 'nick' in c else 'Anonymous'), - 'syntax': c['syntax'].value if 'syntax' in c else settings.default, - 'remember_me': 'nick' in c, - 'remember_syntax': 'syntax' in c, - }) - - def preview(self, mp): - try: - lexername, text = self.get_formatted(mp['syntax'].value, mp['text'].value) - except UnknownSyntaxError: - return self.message('Could not find lexer "%s".' % mp['syntax'].value, 'Error') - - # These values to be unicode in py2; in py3 they will be str which is OK. - nick = b2t(mp['nick'].value or 'Anonymous') - title = b2t(mp['title'].value or 'Untitled') - return self.render_template('view.html', { - 'title': settings.pastebin_name, - 'header': '%s – Preview' % settings.pastebin_name, - 'hash': None, - 'nick': nick, - 'date': '%s UTC' % datetime.datetime.utcnow().ctime(), - 'syntax': lexername, - 'pastetitle': title, - 'text': text, - 'rendered': (lexername or '').startswith('Rendered '), - }) - - def add_paste(self, mp): - nick = b2t(mp['nick'].value or None) - syntax = b2t(mp['syntax'].value or None) - title = b2t(mp['title'].value or None) - text = b2t(mp['text'].value.replace('\r', '') or None) - - hash = ''.join(random.choice(base62_alphabet) for x in range(5)) - - try: - session = db.Session() - paste = db.Paste(hash, nick, datetime.datetime.utcnow(), syntax, title, text, self.environ['REMOTE_ADDR']) - session.add(paste) - session.commit() - finally: - session.close() - - headers = [('Location', '/view/%s' % hash)] - c = SimpleCookie() - if six.PY2: - # In py2 we need nick to be a str, or non-ascii characters will fail with UnicodeDecodeError. - # In py3 it must be a str or we will get garbage in the cookie value. - nick = t2b(nick) - c['nick'] = nick - dt = (datetime.datetime.utcnow() + datetime.timedelta(days = 30)) if 'remember_me' in mp else datetime.datetime.utcfromtimestamp(0) - c['nick']['expires'] = dt.strftime('%a, %d-%b-%y %H:%M:%S GMT') - c['syntax'] = syntax - dt = (datetime.datetime.utcnow() + datetime.timedelta(days = 30)) if 'remember_syntax' in mp else datetime.datetime.utcfromtimestamp(0) - c['syntax']['expires'] = dt.strftime('%a, %d-%b-%y %H:%M:%S GMT') - headers.append(('Set-Cookie', c['nick'].OutputString())) - headers.append(('Set-Cookie', c['syntax'].OutputString())) - self.start_response('302 Found', headers) - return [] - - def get_formatted(self, syntax, text): - if syntax == 'md-render' and has_markdown: - text = markdown.markdown(text, extensions = settings.markdown_extensions) - lexername = 'Rendered markdown' - else: - try: - lex = get_lexer_by_name(syntax or 'text') - except pygments.util.ClassNotFound: - raise UnknownSyntaxError(syntax) - lexername = lex.name - text = highlight(text, lex, self.formatter) - return (lexername, text) - - def view(self): - hash = self.path[1] - - try: - session = db.Session() - try: - cache = session.query(db.Cache).filter_by(paste_hash = hash).one() - paste = cache.paste - except db.NoResultFound: # No cache found, generate it. - try: - paste = session.query(db.Paste).filter_by(hash = hash).one() - except db.NoResultFound: - self.start_response('404 Not Found', []) - return [] - try: - lexername, text = self.get_formatted(paste.syntax, paste.text) - except UnknownSyntaxError: - return self.message('Could not find the lexer "%s".' % paste.syntax, 'Error') - cache = db.Cache(hash, lexername, text) - session.add(cache) - session.commit() - # Workaround for attribute refresh. - paste = cache.paste - finally: - session.close() - - return self.render_template('view.html', { - 'title': '%s – View paste – %s' % (settings.pastebin_name, paste.title or 'Untitled'), - 'header': '%s – View paste' % settings.pastebin_name, - 'hash': hash, - 'date': '%s UTC' % paste.date.ctime(), - 'nick': b2t(paste.nick or 'Anonymous'), - 'syntax': cache.syntax_name, - 'pastetitle': b2t(paste.title or 'Untitled'), - 'text': b2t(cache.text), - 'rendered': (cache.syntax_name or '').startswith('Rendered '), - }) - - def raw(self): - hash = self.path[1] - - try: - session = db.Session() - paste = session.query(db.Paste).filter_by(hash = hash).one() - except db.NoResultFound: - self.start_response('404 Not Found', []) - return [] - finally: - session.close() - - self.start_response('200 OK', [('Content-Type', 'text/plain; charset=UTF-8')]) - return [t2b(paste.text)] - - def full(self): - hash = self.path[1] - - try: - session = db.Session() - try: - cache = session.query(db.Cache).filter_by(paste_hash = hash).one() - paste = cache.paste - except db.NoResultFound: - try: - paste = session.query(db.Paste).filter_by(hash = hash).one() - except db.NoResultFound: - self.start_response('404 Not Found', []) - return [] - try: - lexername, text = self.get_formatted(paste.syntax, paste.text) - except UnknownSyntaxError: - return self.message('Could not find the lexer "%s".' % paste.syntax, 'Error') - cache = db.Cache(hash, lexername, text) - session.add(cache) - session.commit() - # Workaround for attribute refresh. - paste = cache.paste - finally: - session.close() - - return self.render_template('full.html', { - 'title': '%s – %s' % (settings.pastebin_name, paste.title or 'Untitled'), - 'text': b2t(cache.text), - 'rendered': (cache.syntax_name or '').startswith('Rendered '), - }) - - def highlight_stylesheet(self): - self.start_response('200 OK', [('Content-Type', 'text/css')]) - return [t2b(self.formatter.get_style_defs())] - - def static(self): - filename = settings.static_root + os.path.sep + self.path[1] - if not self.path[1] in ('paste.css', 'edit.js', 'view.js') or not os.path.exists(filename): - self.start_response('404 Not Found', [('Content-Type', 'text/html; charset=UTF-8'), ('Location', '/')]) - return ['asdf'] - self.start_response('200 OK', [('Content-Type', mimetypes.guess_type(filename)[0] or 'text/plain; charset=UTF-8')]) - return open(filename, 'rb') - - def __call__(self, environ, start_response): - self.environ = environ - self.start_response = start_response - - path = self.environ['PATH_INFO'].split('/')[1:] - module = path[0] or 'paste' - if module in ('list', 'paste', 'view', 'raw', 'full', 'static', 'highlight_stylesheet'): - self.path = path - return getattr(self, module)() - else: - return self.message('Invalid module requested.', 'Error') - -if __name__ == '__main__': - from wsgiref.simple_server import make_server - httpd = make_server('', 8000, Paste()) - httpd.serve_forever() - -# vim: noet ts=4 diff --git a/pastepy/__init__.py b/pastepy/__init__.py new file mode 100644 index 0000000..0cc4db6 --- /dev/null +++ b/pastepy/__init__.py @@ -0,0 +1,8 @@ +from flask import Flask + +app = Flask(__name__) +app.config.from_pyfile('pastepy.cfg') + +with app.app_context(): + from .pastepy import app as pastepy + app.register_blueprint(pastepy) diff --git a/pastepy/db.py b/pastepy/db.py new file mode 100644 index 0000000..0aa04a1 --- /dev/null +++ b/pastepy/db.py @@ -0,0 +1,68 @@ +from contextlib import contextmanager + +from flask import current_app +from sqlalchemy import create_engine, Column, Integer, String, DateTime, Text, Index, ForeignKey +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker, relation, backref +from sqlalchemy.orm.exc import NoResultFound + +engine = create_engine(current_app.config['DB_PATH']) + +Base = declarative_base(bind = engine) + +class Paste(Base): + __tablename__ = 'paste' + + id = Column(Integer, primary_key = True) + hash = Column(String, unique = True, index = True) + nick = Column(String) + date = Column(DateTime, nullable = False) + syntax = Column(String) + title = Column(String) + text = Column(Text, nullable = False) + ip = Column(String) + + def __init__(self, hash, nick, date, syntax, title, text, ip=None): + self.nick = nick + self.hash = hash + self.date = date + self.syntax = syntax + self.title = title + self.text = text + self.ip = ip + + def __repr__(self): + return '' % (self.id, self.hash, self.nick, self.date.ctime(), self.title) + +class Cache(Base): + __tablename__ = 'cache' + + id = Column(Integer, primary_key = True) + paste_hash = Column(String, ForeignKey('paste.hash'), index = True) + paste = relation(Paste, primaryjoin = paste_hash == Paste.hash, lazy = False) + syntax_name = Column(String) + text = Column(Text, nullable = False) + + def __init__(self, hash, syntax_name, text): + self.paste_hash = hash + self.syntax_name = syntax_name + self.text = text + + def __repr__(self): + return '' % (self.id, self.paste_hash) + +Base.metadata.create_all() +Session = sessionmaker(bind = engine, autoflush = True, autocommit = False) + +@contextmanager +def session_scope(): + session = Session() + try: + session.expire_on_commit = False + yield session + session.commit() + except: + session.rollback() + raise + finally: + session.close() diff --git a/pastepy/pastepy.py b/pastepy/pastepy.py new file mode 100644 index 0000000..750d8fe --- /dev/null +++ b/pastepy/pastepy.py @@ -0,0 +1,169 @@ +import datetime +import random + +from flask import Blueprint, current_app, render_template, request, session, redirect, url_for +try: + import markdown + has_markdown = True +except ImportError: + has_markdown = False +import pygments +from pygments import highlight +from pygments.lexers import get_all_lexers, get_lexer_by_name +from pygments.formatters import HtmlFormatter + +from . import db + +app = Blueprint(__name__, 'pastepy') + +base62_alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + +class PasteError(Exception): pass +class UnknownSyntaxError(PasteError): pass + +class CustomHtmlFormatter(HtmlFormatter): + def wrap(self, source, outfile): + yield 0, '
'
+        line = 1
+        for i, t in source:
+            yield i, '{}'.format(i, t)
+            line += 1
+        yield 0, '
' + +def init_lexers(): + all_lexers = dict([(x[0], x[1][0]) for x in get_all_lexers()]) + lexers = [] + removed = [] + for cat, ls in current_app.config['CATEGORIES']: + for l in ls: + removed.append(l) + lexers.append((cat, [(x, all_lexers[x]) for x in ls if x in all_lexers])) + for l in removed: + try: + del all_lexers[l] + except KeyError: + pass + rendered = [] + if has_markdown: + rendered.append(('Rendered markdown', 'md-render')) + if len(rendered): + lexers.append(('Rendered', rendered)) + lexers.append(('Others' if current_app.config['CATEGORIES'] else 'Syntax', sorted(all_lexers.items(), key = lambda l: l[0].lower()))) + + current_app.config['LEXERS'] = lexers + current_app.config['FORMATTER'] = CustomHtmlFormatter(linenos='table', lineanchors='line', anchorlinenos=True) + +init_lexers() + +@app.route('/') +@app.route('/paste') +def paste(): + context = { + 'title': current_app.config['PASTEBIN_NAME'], + 'header': current_app.config['PASTEBIN_NAME'], + } + return render_template('paste.html', **context) + +def get_formatted(syntax, text): + if syntax == 'md-render' and has_markdown: + text = markdown.markdown(text, extensions=current_app.config['MARKDOWN_EXTENSIONS']) + lexername = 'Rendered markdown' + else: + try: + lex = get_lexer_by_name(syntax or 'text') + except pygments.util.ClassNotFound: + raise UnknownSyntaxError(syntax) + lexername = lex.name + text = highlight(text, lex, current_app.config['FORMATTER']) + return (lexername, text) + +def add_paste(): + nick = request.form.get('nick') + syntax = request.form.get('syntax') + title = request.form.get('title') + text = request.form.get('text').replace('\r', '') + + with db.session_scope() as db_session: + paste_hash = ''.join(random.choice(base62_alphabet) for x in range(5)) + paste = db.Paste(paste_hash, nick, datetime.datetime.utcnow(), syntax, title, text, request.remote_addr) + db_session.add(paste) + + if 'remember_me' in request.form: + session['nick'] = nick + else: + session.pop('nick', None) + if 'remember_syntax' in request.form: + session['syntax'] = syntax + else: + session.pop('syntax', None) + return redirect(url_for('.view_paste', paste_hash=paste_hash)) + +def render_preview(): + try: + lexername, text = get_formatted(request.form['syntax'], request.form['text']) + except UnknownSyntaxError: + abort(500, 'Could not find lexer "{}".'.format(request.form['syntax'])) + + nick = request.form['nick'] or 'Anonymous' + title = request.form['title'] or 'Untitled' + return render_template('view.html', + title='Preview', + hash=None, + nick=nick, + date='{} UTC'.format(datetime.datetime.utcnow().ctime()), + syntax=lexername, + pastetitle=title, + text=text, + rendered=(lexername or '').startswith('Rendered '), + ) + +@app.route('/paste', methods=['POST']) +def post_paste(): + if request.form['type'] == 'Preview': + return render_preview() + if request.form['type'] == 'Paste': + return add_paste() + abort(404) + +@app.route('/view/') +@app.route('/full/', endpoint='view_full') +def view_paste(paste_hash): + with db.session_scope() as db_session: + try: + cache = db_session.query(db.Cache).filter_by(paste_hash=paste_hash).one() + paste = cache.paste + except db.NoResultFound: + try: + paste = db_session.query(db.Paste).filter_by(hash=paste_hash).one() + except db.NoResultFound: + abort(404) + try: + lexername, text = get_formatted(paste.syntax, paste.text) + except UnknownSyntaxError: + abort(500, 'Could not find the lexer "{}"'.format(paste.syntax)) + cache = db.Cache(paste_hash, lexername, text) + db_session.add(cache) + template = 'full.html' if request.endpoint.endswith('.view_full') else 'view.html' + return render_template(template, + title='View paste \u2013 {}'.format(current_app.config['PASTEBIN_NAME'], paste.title or 'Untitled'), + hash=paste_hash, + date='{} UTC'.format(paste.date.ctime()), + nick=paste.nick or 'Anonymous', + syntax=cache.syntax_name, + pastetitle=paste.title or 'Untitled', + text=cache.text, + rendered=(cache.syntax_name or '').startswith('Rendered '), + ) + +@app.route('/highlight_stylesheet') +def highlight_stylesheet(): + return current_app.config['FORMATTER'].get_style_defs(), 200, {'Content-Type': 'text/css'} + +@app.route('/raw/') +def raw(paste_hash): + with db.session_scope() as db_session: + try: + paste = db_session.query(db.Paste).filter_by(hash=paste_hash).one() + except db.NoResultFound: + abort(404) + return paste.text, 200, {'Content-Type': 'text/plain'} diff --git a/pastepy/static/edit.js b/pastepy/static/edit.js new file mode 100644 index 0000000..8e754d8 --- /dev/null +++ b/pastepy/static/edit.js @@ -0,0 +1,83 @@ +function tab_add(t, ti, ss, se) { + t.value = t.value.substr(0, ti) + "\t" + t.value.substr(ti); + t.selectionStart = ss + 1; + t.selectionEnd = se + 1; +} + +function tab_remove(t, ti, ss, se) { + t.value = t.value.substr(0, ti-1) + t.value.substr(ti); + t.selectionStart = ss - 1; + t.selectionEnd = se - 1; +} + +function textarea_handle_tab(t, e) { + if(navigator.userAgent.match("Gecko")) { + keyCode = e.which; + } else { + keyCode = e.keyCode; + } + if(keyCode != 9) + return; + e.preventDefault(); + var ss = t.selectionStart; + var se = t.selectionEnd; + if(ss == se) { + if(e.shiftKey) { + if(t.value[ss-1] == "\t") { + tab_remove(t, ss, ss, se); + } + } else { + tab_add(t, ss, ss, se); + } + } else { + var s; + if(ss < se) + s = t.value.substr(ss, se - ss); + else + s = t.value.substr(se, ss - se); + if(s.indexOf("\n") > -1) { + var nl = s.lastIndexOf("\n"); + if(e.shiftKey) { + while(nl > -1) { + if(s[nl+1] == "\t") { + tab_remove(t, ss + nl + 2, ss, se); + se--; + } + nl = s.lastIndexOf("\n", nl - 2); + } + if(t.value[(ss < se ? ss : se)-1] == "\n" && e.shiftKey) + tab_remove(t, ss+1, ss, se); + if((ss == 0 || se == 0) && t.value[0] == "\t") + tab_remove(t, 1, ss, se); + } else { + while(nl > -1) { + tab_add(t, ss + nl + 1, ss, se); + se++; + if(nl == 0) + break; + nl = s.lastIndexOf("\n", nl - 2); + } + if(ss == 0 || se == 0 || t.value[(ss < se ? ss : se)-1] == "\n") + tab_add(t, ss, ss-1, se); + } + + } else { + var nl = t.value.lastIndexOf("\n", (ss < se ? se : ss) - 1) + 1; + if(e.shiftKey) { + if(t.value[nl] == "\t") { + tab_remove(t, nl + 1, ss, se); + } + } else { + tab_add(t, nl, ss, se); + } + } + } + setTimeout("document.getElementById('" + t.id + "').focus();", 0); +} + +window.onload = function() { + text = document.getElementById("text"); + text.onkeydown = function(event) { + return textarea_handle_tab(text, event); + } +} diff --git a/pastepy/static/paste.css b/pastepy/static/paste.css new file mode 100644 index 0000000..5e59d4d --- /dev/null +++ b/pastepy/static/paste.css @@ -0,0 +1,23 @@ +html, body { margin: 0; padding: 0; font-family: sans-serif; background-color: #fff; color: #000; } +div#page { background: #eee; margin: 1em; } +div#page-header, div#page-content { padding: 1em; } +div#page-header h1 a { color: inherit; } +div#page-header h1 a:hover { text-decoration: none; } +a { color: #00f; text-decoration: none; } +a:hover { text-decoration: underline; } +form#pasteform ul { list-style-type: none; } +textarea { font-family: monospace; } +div#info { font-size: small; color: #bbb; } +span#nick, span#date, span#syntax-type { color: #888; } +div#alt-links { font-size: small; } +div#alt-links a { color: #44f; } +div.paste-rendered { padding: 1em; } +div#paste div.paste-rendered { background-color: #fff; margin-top: 1em; } +.highlighttable { width: 100%; padding-top: 1em; } +.highlighttable td.code { width: 100%; background-color: #fff; } +.highlighttable td { vertical-align: top; } +.highlighttable pre { margin: 0; padding: 0; } +.highlighttable .linenos { text-align: right; padding-left: .5em; padding-right: .5em; } +.highlighttable .linenos a { color: #888; } +.highlighttable .selected { display: block; background-color: #cfc; } +.highlighttable .code { tab-size: 4; } diff --git a/pastepy/static/view.js b/pastepy/static/view.js new file mode 100644 index 0000000..fd6db03 --- /dev/null +++ b/pastepy/static/view.js @@ -0,0 +1,26 @@ +function set_highlight(line) { + var line = 'codeline-' + line + var codeline = document.getElementById(line); + if (codeline) { + codeline.className = 'selected'; + } +} +function cleanup() { + var elements = document.getElementsByClassName('selected'); + for (var i = 0; i < elements.length; i++) { + elements[i].className = ''; + } +} +window.onload = function(event) { + var line = document.location.hash.substr(6); + if (line) { + set_highlight(line); + } + var as = document.getElementsByClassName('linenodiv')[0].getElementsByTagName('a'); + for (var i = 0; i < as.length; i++) { + as[i].onclick = function(event) { + cleanup(); + set_highlight(event.target.text.trim()); + } + } +} diff --git a/pastepy/templates/base.html b/pastepy/templates/base.html new file mode 100644 index 0000000..e208b6b --- /dev/null +++ b/pastepy/templates/base.html @@ -0,0 +1,20 @@ + + + + {{ config.PASTEBIN_NAME }}{% if title %} – {{ title }}{% endif %} + +{% block head %} +{% endblock %} + + +
+ +
+{% block content %} +{% endblock %} +
+
+ + diff --git a/pastepy/templates/full.html b/pastepy/templates/full.html new file mode 100644 index 0000000..c60126e --- /dev/null +++ b/pastepy/templates/full.html @@ -0,0 +1,18 @@ + + + + {{ title }} + + + + + +{% if rendered %} +
+{% endif %} +{{ text|safe }} +{% if rendered %} +
+{% endif %} + + diff --git a/pastepy/templates/paste.html b/pastepy/templates/paste.html new file mode 100644 index 0000000..9a22e76 --- /dev/null +++ b/pastepy/templates/paste.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} +{% block head %} + +{% endblock %} +{% block content %} +
+
    +
  • + + + +
  • +
  • + + + +
  • +
  • +
  • +
  • + + +
  • +
+
+{% endblock %} diff --git a/pastepy/templates/view.html b/pastepy/templates/view.html new file mode 100644 index 0000000..b0b114c --- /dev/null +++ b/pastepy/templates/view.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% block head %} + + +{% endblock %} +{% block content %} +

New paste

+
+

{{ pastetitle }}

+
Pasted by {{ nick }} on {{date }} + {% if syntax %} as {{ syntax }}{% endif %} +
+ + {% if rendered %} +
+ {% endif %} + {{ text|safe }} + {% if rendered %} +
+ {% endif %} +
+{% endblock %} diff --git a/static/edit.js b/static/edit.js deleted file mode 100644 index 8e754d8..0000000 --- a/static/edit.js +++ /dev/null @@ -1,83 +0,0 @@ -function tab_add(t, ti, ss, se) { - t.value = t.value.substr(0, ti) + "\t" + t.value.substr(ti); - t.selectionStart = ss + 1; - t.selectionEnd = se + 1; -} - -function tab_remove(t, ti, ss, se) { - t.value = t.value.substr(0, ti-1) + t.value.substr(ti); - t.selectionStart = ss - 1; - t.selectionEnd = se - 1; -} - -function textarea_handle_tab(t, e) { - if(navigator.userAgent.match("Gecko")) { - keyCode = e.which; - } else { - keyCode = e.keyCode; - } - if(keyCode != 9) - return; - e.preventDefault(); - var ss = t.selectionStart; - var se = t.selectionEnd; - if(ss == se) { - if(e.shiftKey) { - if(t.value[ss-1] == "\t") { - tab_remove(t, ss, ss, se); - } - } else { - tab_add(t, ss, ss, se); - } - } else { - var s; - if(ss < se) - s = t.value.substr(ss, se - ss); - else - s = t.value.substr(se, ss - se); - if(s.indexOf("\n") > -1) { - var nl = s.lastIndexOf("\n"); - if(e.shiftKey) { - while(nl > -1) { - if(s[nl+1] == "\t") { - tab_remove(t, ss + nl + 2, ss, se); - se--; - } - nl = s.lastIndexOf("\n", nl - 2); - } - if(t.value[(ss < se ? ss : se)-1] == "\n" && e.shiftKey) - tab_remove(t, ss+1, ss, se); - if((ss == 0 || se == 0) && t.value[0] == "\t") - tab_remove(t, 1, ss, se); - } else { - while(nl > -1) { - tab_add(t, ss + nl + 1, ss, se); - se++; - if(nl == 0) - break; - nl = s.lastIndexOf("\n", nl - 2); - } - if(ss == 0 || se == 0 || t.value[(ss < se ? ss : se)-1] == "\n") - tab_add(t, ss, ss-1, se); - } - - } else { - var nl = t.value.lastIndexOf("\n", (ss < se ? se : ss) - 1) + 1; - if(e.shiftKey) { - if(t.value[nl] == "\t") { - tab_remove(t, nl + 1, ss, se); - } - } else { - tab_add(t, nl, ss, se); - } - } - } - setTimeout("document.getElementById('" + t.id + "').focus();", 0); -} - -window.onload = function() { - text = document.getElementById("text"); - text.onkeydown = function(event) { - return textarea_handle_tab(text, event); - } -} diff --git a/static/paste.css b/static/paste.css deleted file mode 100644 index 5e59d4d..0000000 --- a/static/paste.css +++ /dev/null @@ -1,23 +0,0 @@ -html, body { margin: 0; padding: 0; font-family: sans-serif; background-color: #fff; color: #000; } -div#page { background: #eee; margin: 1em; } -div#page-header, div#page-content { padding: 1em; } -div#page-header h1 a { color: inherit; } -div#page-header h1 a:hover { text-decoration: none; } -a { color: #00f; text-decoration: none; } -a:hover { text-decoration: underline; } -form#pasteform ul { list-style-type: none; } -textarea { font-family: monospace; } -div#info { font-size: small; color: #bbb; } -span#nick, span#date, span#syntax-type { color: #888; } -div#alt-links { font-size: small; } -div#alt-links a { color: #44f; } -div.paste-rendered { padding: 1em; } -div#paste div.paste-rendered { background-color: #fff; margin-top: 1em; } -.highlighttable { width: 100%; padding-top: 1em; } -.highlighttable td.code { width: 100%; background-color: #fff; } -.highlighttable td { vertical-align: top; } -.highlighttable pre { margin: 0; padding: 0; } -.highlighttable .linenos { text-align: right; padding-left: .5em; padding-right: .5em; } -.highlighttable .linenos a { color: #888; } -.highlighttable .selected { display: block; background-color: #cfc; } -.highlighttable .code { tab-size: 4; } diff --git a/static/view.js b/static/view.js deleted file mode 100644 index c855609..0000000 --- a/static/view.js +++ /dev/null @@ -1,5 +0,0 @@ -window.onload = function() { - var line = 'code' + document.location.hash.substr(1); - var codeline = document.getElementById(line); - codeline.className = 'selected'; -} diff --git a/templates/base.html b/templates/base.html deleted file mode 100644 index 196a03e..0000000 --- a/templates/base.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - {{ title }} - -{% block head %} -{% endblock %} - - -
- -
-{% block content %} -{% endblock %} -
-
- - diff --git a/templates/full.html b/templates/full.html deleted file mode 100644 index dfa0606..0000000 --- a/templates/full.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - {{ title }} - - - - - -{% if rendered %} -
-{% endif %} -{{ text }} -{% if rendered %} -
-{% endif %} - - diff --git a/templates/message.html b/templates/message.html deleted file mode 100644 index 540b64a..0000000 --- a/templates/message.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "base.html" %} -{% block content %} -

New paste

- {{ text }} -{% endblock %} diff --git a/templates/paste.html b/templates/paste.html deleted file mode 100644 index e22f76d..0000000 --- a/templates/paste.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "base.html" %} -{% block head %} - -{% endblock %} -{% block content %} -
-
    -
  • - - - -
  • -
  • - - - -
  • -
  • -
  • -
  • - - -
  • -
-
-{% endblock %} diff --git a/templates/view.html b/templates/view.html deleted file mode 100644 index a1d00a7..0000000 --- a/templates/view.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "base.html" %} -{% block head %} - - -{% endblock %} -{% block content %} -

New paste

-
-

{{ pastetitle }}

-
Pasted by {{ nick }} on {{date }} - {% if syntax %} as {{ syntax }}{% endif %} -
- - {% if rendered %} -
- {% endif %} - {{ text }} - {% if rendered %} -
- {% endif %} -
-{% endblock %} -- cgit v1.2.3