1
0
mirror of https://github.com/Tygs/0bin.git synced 2023-08-10 21:13:00 +03:00

jQuery fully removed, clipboard fixed

This commit is contained in:
ksamuel 2020-08-11 11:55:29 +02:00
parent 722fb45b51
commit e13cead89b
15 changed files with 13219 additions and 1749 deletions

View File

@ -10,9 +10,7 @@
be pasted in it. The idea is that one can (probably...) not be legally entitled
to `moderate the pastebin content`_ as they have no way to decrypt it.
It's an Python implementation of the
`zerobin project`_ under the `WTF licence`_. It's easy to
install even if you know nothing about Python.
It's an Python implementation of the `zerobin project`_, created by sebsauvage, under the `WTF licence`_.
For now tested with IE9, and the last opera, safari, chrome and FF.
@ -22,7 +20,7 @@ but in short::
pip install zerobin
zerobin
0bin runs on Python 2.7 and Python 3.4.
0bin runs on Python 3.7.
How it works
=============
@ -74,7 +72,6 @@ Technologies used
- Cherrypy_ (server only)
- `node.js`_ (for optional command-line tool only)
Known issues
============

View File

@ -31,6 +31,7 @@ def runserver(
server="cherrypy",
):
debug = True
if version:
print("0bin V%s" % settings.VERSION)
sys.exit(0)

View File

@ -2,6 +2,7 @@
# coding: utf-8
from __future__ import unicode_literals, absolute_import, print_function
import pdb
"""
Script including controller, rooting, and dependency management.
@ -24,84 +25,90 @@ from datetime import datetime, timedelta
# add project dir and libs dir to the PYTHON PATH to ensure they are
# importable
from zerobin.utils import (settings, SettingsValidationError,
drop_privileges, dmerge)
from zerobin.utils import settings, SettingsValidationError, drop_privileges, dmerge
import bottle
from bottle import (Bottle, run, static_file, view, request)
from bottle import Bottle, run, static_file, view, request
from zerobin.paste import Paste
app = Bottle()
GLOBAL_CONTEXT = {
'settings': settings,
'pastes_count': Paste.get_pastes_count(),
'refresh_counter': datetime.now()
"settings": settings,
"pastes_count": Paste.get_pastes_count(),
"refresh_counter": datetime.now(),
}
@app.route('/')
@view('home')
@app.route("/")
@view("home")
def index():
return GLOBAL_CONTEXT
@app.route('/faq/')
@view('faq')
@app.route("/faq/")
@view("faq")
def faq():
return GLOBAL_CONTEXT
@app.route('/paste/create', method='POST')
@app.route("/paste/create", method="POST")
def create_paste():
try:
body = urlparse.parse_qs(request.body.read(int(settings.MAX_SIZE * 1.1)))
except ValueError:
return {'status': 'error', 'message': "Wrong data payload."}
return {"status": "error", "message": "Wrong data payload."}
try:
content = "".join(x.decode('utf8') for x in body[b'content'])
content = "".join(x.decode("utf8") for x in body[b"content"])
except (UnicodeDecodeError, KeyError):
return {'status': 'error',
'message': "Encoding error: the paste couldn't be saved."}
return {
"status": "error",
"message": "Encoding error: the paste couldn't be saved.",
}
if '{"iv":' not in content: # reject silently non encrypted content
return {'status': 'error', 'message': "Wrong data payload."}
return {"status": "error", "message": "Wrong data payload."}
# check size of the paste. if more than settings return error
# without saving paste. prevent from unusual use of the
# system. need to be improved
if 0 < len(content) < settings.MAX_SIZE:
expiration = body.get(b'expiration', ['burn_after_reading'])[0]
paste = Paste(expiration=expiration.decode('utf8'), content=content,
uuid_length=settings.PASTE_ID_LENGTH)
expiration = body.get(b"expiration", [b"burn_after_reading"])[0]
paste = Paste(
expiration=expiration.decode("utf8"),
content=content,
uuid_length=settings.PASTE_ID_LENGTH,
)
paste.save()
# display counter
if settings.DISPLAY_COUNTER:
#increment paste counter
# increment paste counter
paste.increment_counter()
# if refresh time elapsed pick up new counter value
now = datetime.now()
timeout = (GLOBAL_CONTEXT['refresh_counter']
+ timedelta(seconds=settings.REFRESH_COUNTER))
timeout = GLOBAL_CONTEXT["refresh_counter"] + timedelta(
seconds=settings.REFRESH_COUNTER
)
if timeout < now:
GLOBAL_CONTEXT['pastes_count'] = Paste.get_pastes_count()
GLOBAL_CONTEXT['refresh_counter'] = now
GLOBAL_CONTEXT["pastes_count"] = Paste.get_pastes_count()
GLOBAL_CONTEXT["refresh_counter"] = now
return {'status': 'ok', 'paste': paste.uuid}
return {"status": "ok", "paste": paste.uuid}
return {'status': 'error',
'message': "Serveur error: the paste couldn't be saved. "
"Please try later."}
return {
"status": "error",
"message": "Serveur error: the paste couldn't be saved. " "Please try later.",
}
@app.route('/paste/:paste_id')
@view('paste')
@app.route("/paste/:paste_id")
@view("paste")
def display_paste(paste_id):
now = datetime.now()
@ -115,9 +122,8 @@ def display_paste(paste_id):
# we don't delete the paste because it means it's the redirection
# to the paste that happens during the paste creation
try:
keep_alive = paste.expiration.split('#')[1]
keep_alive = datetime.strptime(keep_alive,
'%Y-%m-%d %H:%M:%S.%f')
keep_alive = paste.expiration.split("#")[1]
keep_alive = datetime.strptime(keep_alive, "%Y-%m-%d %H:%M:%S.%f")
keep_alive = now < keep_alive + timedelta(seconds=10)
except IndexError:
keep_alive = False
@ -131,35 +137,34 @@ def display_paste(paste_id):
except (TypeError, ValueError):
return error404(ValueError)
context = {'paste': paste, 'keep_alive': keep_alive}
context = {"paste": paste, "keep_alive": keep_alive}
return dmerge(context, GLOBAL_CONTEXT)
@app.error(404)
@view('404')
@view("404")
def error404(code):
return GLOBAL_CONTEXT
@app.route('/static/<filename:path>')
@app.route("/static/<filename:path>")
def server_static(filename):
return static_file(filename, root=settings.STATIC_FILES_ROOT)
def get_app(debug=None, settings_file='',
compressed_static=None, settings=settings):
def get_app(debug=None, settings_file="", compressed_static=None, settings=settings):
"""
Return a tuple (settings, app) configured using passed
parameters and/or a setting file.
"""
settings_file = settings_file or os.environ.get('ZEROBIN_SETTINGS_FILE')
settings_file = settings_file or os.environ.get("ZEROBIN_SETTINGS_FILE")
if settings_file:
settings.update_with_file(os.path.realpath(settings_file))
if settings.PASTE_ID_LENGTH < 4:
raise SettingsValidationError('PASTE_ID_LENGTH cannot be lower than 4')
raise SettingsValidationError("PASTE_ID_LENGTH cannot be lower than 4")
if compressed_static is not None:
settings.COMPRESSED_STATIC_FILES = compressed_static

View File

@ -1,223 +1,239 @@
[v-cloak] {
display: none
}
.noscript {
position: relative;
top: 25%;
border: 25px solid red;
}
/* logo */
.brand {
font-size: 38px !important;
padding: 0 55px 3px !important;
font-size: 38px !important;
padding: 0 55px 3px !important;
text-shadow: 0 1px 0 rgba(255, 255, 255, .1), 0 0 30px rgba(255, 255, 255, .125);
-webkit-transition: all .2s linear;
-moz-transition: all .2s linear;
-o-transition: all .2s linear;
-ms-transition: all .2s linear;
transition: all .2s linear;
text-shadow: 0 1px 0 rgba(255, 255, 255, .1), 0 0 30px rgba(255, 255, 255, .125);
-webkit-transition: all .2s linear;
-moz-transition: all .2s linear;
-o-transition: all .2s linear;
-ms-transition: all .2s linear;
transition: all .2s linear;
}
.brand span {
font-size: 48px;
line-height: 0;
font-size: 48px;
line-height: 0;
}
.brand em {
display: inline;
color: #D40202;
font-size: 27px;
display: inline;
color: #D40202;
font-size: 27px;
}
.about {
line-height: 13px;
font-style: italic;
text-align: right;
padding-top: 9px;
margin-bottom: 0 !important;
line-height: 13px;
font-style: italic;
text-align: right;
padding-top: 9px;
margin-bottom: 0 !important;
}
.center {
text-align: center;
text-align: center;
}
.about span{
font-size: 10px;
.about span {
font-size: 10px;
}
/* body & other stuff */
body {
padding-top: 60px;
padding-bottom: 40px;
padding-top: 60px;
padding-bottom: 40px;
}
.sidebar-nav {
padding: 9px 0;
padding: 9px 0;
}
select {
width: 135px;
width: 135px;
}
label {
display: inline;
margin-left: 18px;
font-style: italic;
font-size: 11px;
color: #888;
display: inline;
margin-left: 18px;
font-style: italic;
font-size: 11px;
color: #888;
}
ul, ol {
padding: 0;
margin: 0;
ul,
ol {
padding: 0;
margin: 0;
}
li {
margin-left: -9px;
margin-left: -9px;
}
p {
margin: 0 0 20px;
margin: 0 0 20px;
}
.grey {
color: #999;
color: #999;
}
.nav-list {
padding-right: 0px !important;
font-size: 12px;
padding-right: 0px !important;
font-size: 12px;
}
blockquote {
width: 630px;
float: left;
width: 630px;
float: left;
}
h4 p {
float: left;
font-size: 80px;
text-shadow: 1px 3px 1px #DDD, 0 0 4px #333;
-webkit-transition: all 0.2s linear;
-o-transition: all .2s linear;
-ms-transition: all .2s linear;
-moz-transition: all .2s linear;
transition: all .2s linear;
margin-right: 7px;
margin-top: 3px;
float: left;
font-size: 80px;
text-shadow: 1px 3px 1px #DDD, 0 0 4px #333;
-webkit-transition: all 0.2s linear;
-o-transition: all .2s linear;
-ms-transition: all .2s linear;
-moz-transition: all .2s linear;
transition: all .2s linear;
margin-right: 7px;
margin-top: 3px;
}
h4#pixels-total {
position: relative;
width: 166px;
float: right;
margin: 8px 0 0 0;
padding: 0 0 0 54px;
font-size: 1.1em;
line-height: 1.4;
font-weight: normal;
color: #777;
-webkit-border-top-right-radius: 6px;
-webkit-border-top-left-radius: 20px;
-moz-border-top-right-radius: 6px;
-moz-border-top-left-radius: 20px;
border-top-right-radius: 6px;
border-top-left-radius: 20px;
position: relative;
width: 166px;
float: right;
margin: 8px 0 0 0;
padding: 0 0 0 54px;
font-size: 1.1em;
line-height: 1.4;
font-weight: normal;
color: #777;
-webkit-border-top-right-radius: 6px;
-webkit-border-top-left-radius: 20px;
-moz-border-top-right-radius: 6px;
-moz-border-top-left-radius: 20px;
border-top-right-radius: 6px;
border-top-left-radius: 20px;
}
.greetings {
clear: both;
margin: 0 auto;
text-align: center;
margin-top: 40px;
clear: both;
margin: 0 auto;
text-align: center;
margin-top: 40px;
}
.alert .title {
display:block;
display: block;
}
/* Home */
.btn-group {
float:left;
float: left;
}
html.file-upload p.file-upload {
float: left;
margin: 22px 0px 0px 21px;
display: none;
float: left;
margin: 22px 0px 0px 21px;
display: none;
}
html.file-upload p.file-upload {
display:inherit;
display: inherit;
}
html.no-file-upload p.file-upload {
display:none;
display: none;
}
input.btn-upload {
position: relative;
left: -6px;
width: 100px;
z-index: 1;
margin-top: -13px;
position: relative;
left: -6px;
width: 100px;
z-index: 1;
margin-top: -13px;
}
input.hide-upload {
position: relative;
left: -110px;
-moz-opacity: 0;
filter: alpha(opacity=0);
opacity: 0 ;
z-index: 2;
width: 100px;
margin-top: -20px;
cursor: pointer;
cursor: hand;
height: 49px;
position: relative;
left: -110px;
-moz-opacity: 0;
filter: alpha(opacity=0);
opacity: 0;
z-index: 2;
width: 100px;
margin-top: -20px;
cursor: pointer;
cursor: hand;
height: 49px;
}
/* Paste Page */
#paste-content {
background-color: white;
padding:1em;
background-color: white;
padding: 1em;
}
#paste-content.linenums {
padding-left:0;
padding-left: 0;
}
.submit-form {
display:none;
display: none;
}
.paste-option {
float:right;
float: right;
}
a#clip-button.hover{
cursor:pointer;
text-decoration:underline;
a#clip-button.hover {
cursor: pointer;
text-decoration: underline;
}
li.L0, li.L1, li.L2, li.L3, li.L4,
li.L5, li.L6, li.L7, li.L8, li.L9
{
list-style-type: decimal;
background: inherit;
li.L0,
li.L1,
li.L2,
li.L3,
li.L4,
li.L5,
li.L6,
li.L7,
li.L8,
li.L9 {
list-style-type: decimal;
background: inherit;
}
.prettyprint.linenums {
-webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
-moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
-moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
}
/* Specify class=linenums on a pre to get line numbering */
ol.linenums {
margin: 0 0 0 55px; /* IE indents via margin-left */
margin: 0 0 0 55px;
/* IE indents via margin-left */
}
ol.linenums li {
color: #bebec5;
line-height: 18px;
@ -231,160 +247,154 @@ ol.linenums li {
}
pre {
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, monospace, serif;
line-height: 21px;
font-size: 12px;
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, monospace, serif;
line-height: 21px;
font-size: 12px;
}
.kwd {
color: #66F;
color: #66F;
}
.pun, .opn, .clo {
color: #0A0;
.pun,
.opn,
.clo {
color: #0A0;
}
.lit {
color: #933;
color: #933;
}
.com {
color: #C0C;
color: #C0C;
}
/* Common css */
form {
padding-bottom:3em !important;
padding-right: 17px;
padding-bottom: 3em !important;
padding-right: 17px;
}
form textarea {
overflow-y:auto;
min-height:250px;
overflow-y: auto;
min-height: 250px;
}
button.btn, input[type="submit"].btn {
margin-left: 5px;
button.btn,
input[type="submit"].btn {
margin-left: 5px;
}
.well {
padding-bottom: 40px;
padding-right: 17px;
padding-bottom: 40px;
padding-right: 17px;
}
.legal {
margin: 0 auto;
width: 300px;
text-align: center;
margin-top: 30px;
margin: 0 auto;
width: 300px;
text-align: center;
margin-top: 30px;
}
.btn {
margin-left: 5px;
margin-left: 5px;
}
.btn-primary, .btn-danger {
position:relative;
top:-4px;
}
#alert-template {
display: none;
.btn-primary,
.btn-danger {
position: relative;
top: -4px;
}
/** Progress bar */
.progress {
display:none;
width: 100%;
}
.progress .bar {
width: 25%;
text-indent: 10px;
text-align:left;
width: 25%;
text-indent: 10px;
text-align: left;
}
.lnk-option canvas {
vertical-align:middle;
margin-right:10px;
vertical-align: middle;
margin-right: 10px;
}
/* Previous paste list */
.previous-pastes .item {
margin-top:5px;
vertical-align:middle;
line-height:24px;
padding-left:1em;
margin-top: 5px;
vertical-align: middle;
line-height: 24px;
padding-left: 1em;
}
li.item {
margin-left: -13px;
margin-right: -5px;
margin-left: -13px;
margin-right: -5px;
}
.previous-pastes canvas {
display:block;
float:left;
margin-right:5px;
display: block;
float: left;
margin-right: 5px;
}
html.local-storage .no-local-storage {
display:none;
display: none;
}
html.no-local-storage .local-storage {
display:none;
display: none;
}
canvas {
border: 1px solid white;
}
#wrap-content {
display: none;
border: 1px solid white;
}
.noscript {
text-align: center;
color: red;
font-weight: bold;
text-align: center;
color: red;
font-weight: bold;
}
#faq dt {
margin:2em 0 1em 0;
margin: 2em 0 1em 0;
}
#faq p {
margin:1em;
margin: 1em;
}
#force-coloration {
text-decoration:underline;
text-decoration: underline;
}
#expiration-tag {
float:right;
margin:1em;
background:grey;
color:white;
font-size:0.8em;
padding:0 1ex;
opacity: 0.5;
filter: alpha(opacity=50);
font-weight:bold;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-moz-background-clip: padding;
-webkit-background-clip: padding-box;
background-clip: padding-box;
float: right;
margin: 1em;
background: grey;
color: white;
font-size: 0.8em;
padding: 0 1ex;
opacity: 0.5;
filter: alpha(opacity=50);
font-weight: bold;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-moz-background-clip: padding;
-webkit-background-clip: padding-box;
background-clip: padding-box;
}
#content.hover {
background-color: #eee;
}
background-color: #eee;
}

View File

@ -1,311 +0,0 @@
// Simple Set Clipboard System
// Author: Joseph Huckaby
var ZeroClipboard = {
version: "1.0.7",
clients: {}, // registered upload clients on page, indexed by id
moviePath: 'ZeroClipboard.swf', // URL to movie
nextId: 1, // ID of next movie
$: function(thingy) {
// simple DOM lookup utility function
if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
if (!thingy.addClass) {
// extend element with a few useful methods
thingy.hide = function() { this.style.display = 'none'; };
thingy.show = function() { this.style.display = ''; };
thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
thingy.removeClass = function(name) {
var classes = this.className.split(/\s+/);
var idx = -1;
for (var k = 0; k < classes.length; k++) {
if (classes[k] == name) { idx = k; k = classes.length; }
}
if (idx > -1) {
classes.splice( idx, 1 );
this.className = classes.join(' ');
}
return this;
};
thingy.hasClass = function(name) {
return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
};
}
return thingy;
},
setMoviePath: function(path) {
// set path to ZeroClipboard.swf
this.moviePath = path;
},
dispatch: function(id, eventName, args) {
// receive event from flash movie, send to client
var client = this.clients[id];
if (client) {
client.receiveEvent(eventName, args);
}
},
register: function(id, client) {
// register new client to receive events
this.clients[id] = client;
},
getDOMObjectPosition: function(obj, stopObj) {
// get absolute coordinates for dom element
var info = {
left: 0,
top: 0,
width: obj.width ? obj.width : obj.offsetWidth,
height: obj.height ? obj.height : obj.offsetHeight
};
while (obj && (obj != stopObj)) {
info.left += obj.offsetLeft;
info.top += obj.offsetTop;
obj = obj.offsetParent;
}
return info;
},
Client: function(elem) {
// constructor for new simple upload client
this.handlers = {};
// unique ID
this.id = ZeroClipboard.nextId++;
this.movieId = 'ZeroClipboardMovie_' + this.id;
// register client with singleton to receive flash events
ZeroClipboard.register(this.id, this);
// create movie
if (elem) this.glue(elem);
}
};
ZeroClipboard.Client.prototype = {
id: 0, // unique ID for us
ready: false, // whether movie is ready to receive events or not
movie: null, // reference to movie object
clipText: '', // text to copy to clipboard
handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
cssEffects: true, // enable CSS mouse effects on dom container
handlers: null, // user event handlers
glue: function(elem, appendElem, stylesToAdd) {
// glue to DOM element
// elem can be ID or actual DOM element object
this.domElement = ZeroClipboard.$(elem);
// float just above object, or zIndex 99 if dom element isn't set
var zIndex = 99;
if (this.domElement.style.zIndex) {
zIndex = parseInt(this.domElement.style.zIndex, 10) + 1;
}
if (typeof(appendElem) == 'string') {
appendElem = ZeroClipboard.$(appendElem);
}
else if (typeof(appendElem) == 'undefined') {
appendElem = document.getElementsByTagName('body')[0];
}
// find X/Y position of domElement
var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem);
// create floating DIV above element
this.div = document.createElement('div');
var style = this.div.style;
style.position = 'absolute';
style.left = '' + box.left + 'px';
style.top = '' + box.top + 'px';
style.width = '' + box.width + 'px';
style.height = '' + box.height + 'px';
style.zIndex = zIndex;
if (typeof(stylesToAdd) == 'object') {
for (addedStyle in stylesToAdd) {
style[addedStyle] = stylesToAdd[addedStyle];
}
}
//style.backgroundColor = '#f00'; // debug
appendElem.appendChild(this.div);
this.div.innerHTML = this.getHTML( box.width, box.height );
},
getHTML: function(width, height) {
// return HTML for movie
var html = '';
var flashvars = 'id=' + this.id +
'&width=' + width +
'&height=' + height;
if (navigator.userAgent.match(/MSIE/)) {
// IE gets an OBJECT tag
var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
}
else {
// all other browsers get an EMBED tag
html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
}
return html;
},
hide: function() {
// temporarily hide floater offscreen
if (this.div) {
this.div.style.left = '-2000px';
}
},
show: function() {
// show ourselves after a call to hide()
this.reposition();
},
destroy: function() {
// destroy control and floater
if (this.domElement && this.div) {
this.hide();
this.div.innerHTML = '';
var body = document.getElementsByTagName('body')[0];
try { body.removeChild( this.div ); } catch(e) {;}
this.domElement = null;
this.div = null;
}
},
reposition: function(elem) {
// reposition our floating div, optionally to new container
// warning: container CANNOT change size, only position
if (elem) {
this.domElement = ZeroClipboard.$(elem);
if (!this.domElement) this.hide();
}
if (this.domElement && this.div) {
var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
var style = this.div.style;
style.left = '' + box.left + 'px';
style.top = '' + box.top + 'px';
}
},
setText: function(newText) {
// set text to be copied to clipboard
this.clipText = newText;
if (this.ready) this.movie.setText(newText);
},
addEventListener: function(eventName, func) {
// add user event listener for event
// event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
eventName = eventName.toString().toLowerCase().replace(/^on/, '');
if (!this.handlers[eventName]) this.handlers[eventName] = [];
this.handlers[eventName].push(func);
},
setHandCursor: function(enabled) {
// enable hand cursor (true), or default arrow cursor (false)
this.handCursorEnabled = enabled;
if (this.ready) this.movie.setHandCursor(enabled);
},
setCSSEffects: function(enabled) {
// enable or disable CSS effects on DOM container
this.cssEffects = !!enabled;
},
receiveEvent: function(eventName, args) {
// receive event from flash
eventName = eventName.toString().toLowerCase().replace(/^on/, '');
// special behavior for certain events
switch (eventName) {
case 'load':
// movie claims it is ready, but in IE this isn't always the case...
// bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
this.movie = document.getElementById(this.movieId);
if (!this.movie) {
var self = this;
setTimeout( function() { self.receiveEvent('load', null); }, 1 );
return;
}
// firefox on pc needs a "kick" in order to set these in certain cases
if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
var self = this;
setTimeout( function() { self.receiveEvent('load', null); }, 100 );
this.ready = true;
return;
}
this.ready = true;
this.movie.setText( this.clipText );
this.movie.setHandCursor( this.handCursorEnabled );
break;
case 'mouseover':
if (this.domElement && this.cssEffects) {
this.domElement.addClass('hover');
if (this.recoverActive) this.domElement.addClass('active');
}
break;
case 'mouseout':
if (this.domElement && this.cssEffects) {
this.recoverActive = false;
if (this.domElement.hasClass('active')) {
this.domElement.removeClass('active');
this.recoverActive = true;
}
this.domElement.removeClass('hover');
}
break;
case 'mousedown':
if (this.domElement && this.cssEffects) {
this.domElement.addClass('active');
}
break;
case 'mouseup':
if (this.domElement && this.cssEffects) {
this.domElement.removeClass('active');
this.recoverActive = false;
}
break;
} // switch eventName
if (this.handlers[eventName]) {
for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
var func = this.handlers[eventName][idx];
if (typeof(func) == 'function') {
// actual function reference
func(this, args);
}
else if ((typeof(func) == 'object') && (func.length == 2)) {
// PHP style object + method, i.e. [myObject, 'myMethod']
func[0][ func[1] ](this, args);
}
else if (typeof(func) == 'string') {
// name of function
window[func](this, args);
}
} // foreach event handler defined
} // user defined handler for event
}
};

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,162 +0,0 @@
/**
* @name Elastic
* @descripton Elastic is jQuery plugin that grow and shrink your textareas automatically
* @version 1.6.11
* @requires jQuery 1.2.6+
*
* @author Jan Jarfalk
* @author-email jan.jarfalk@unwrongest.com
* @author-website http://www.unwrongest.com
*
* @licence MIT License - http://www.opensource.org/licenses/mit-license.php
*/
(function($){
jQuery.fn.extend({
elastic: function() {
// We will create a div clone of the textarea
// by copying these attributes from the textarea to the div.
var mimics = [
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'fontSize',
'lineHeight',
'fontFamily',
'width',
'fontWeight',
'border-top-width',
'border-right-width',
'border-bottom-width',
'border-left-width',
'borderTopStyle',
'borderTopColor',
'borderRightStyle',
'borderRightColor',
'borderBottomStyle',
'borderBottomColor',
'borderLeftStyle',
'borderLeftColor'
];
return this.each( function() {
// Elastic only works on textareas
if ( this.type !== 'textarea' ) {
return false;
}
var $textarea = jQuery(this),
$twin = jQuery('<div />').css({
'position' : 'absolute',
'display' : 'none',
'word-wrap' : 'break-word',
'white-space' :'pre-wrap'
}),
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
goalheight = 0;
// Opera returns max-height of -1 if not set
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
// Append the twin to the DOM
// We are going to meassure the height of this, not the textarea.
$twin.appendTo($textarea.parent());
// Copy the essential styles (mimics) from the textarea to the twin
var i = mimics.length;
while(i--){
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
}
// Updates the width of the twin. (solution for textareas with widths in percent)
function setTwinWidth(){
var curatedWidth = Math.floor(parseInt($textarea.width(),10));
if($twin.width() !== curatedWidth){
$twin.css({'width': curatedWidth + 'px'});
// Update height of textarea
update(true);
}
}
// Sets a given height and overflow state on the textarea
function setHeightAndOverflow(height, overflow){
var curratedHeight = Math.floor(parseInt(height,10));
if($textarea.height() !== curratedHeight){
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
}
}
// This function will update the height of the textarea if necessary
function update(forced) {
// Get curated content from the textarea.
var textareaContent = $textarea.val().replace(/&/g,'&amp;').replace(/ {2}/g, '&nbsp;').replace(/<|>/g, '&gt;').replace(/\n/g, '<br />');
// Compare curated content with curated twin.
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
if(forced || textareaContent+'&nbsp;' !== twinContent){
// Add an extra white space so new rows are added when you are at the end of a row.
$twin.html(textareaContent+'&nbsp;');
// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
var goalheight = $twin.height()+lineHeight;
if(goalheight >= maxheight) {
setHeightAndOverflow(maxheight,'auto');
} else if(goalheight <= minheight) {
setHeightAndOverflow(minheight,'hidden');
} else {
setHeightAndOverflow(goalheight,'hidden');
}
}
}
}
// Hide scrollbars
$textarea.css({'overflow':'hidden'});
// Update textarea size on keyup, change, cut and paste
$textarea.bind('keyup change cut paste', function(){
update();
});
// Update width of twin if browser or textarea is resized (solution for textareas with widths in percent)
$(window).bind('resize', setTwinWidth);
$textarea.bind('resize', setTwinWidth);
$textarea.bind('update', update);
// Compact textarea on blur
$textarea.bind('blur',function(){
if($twin.height() < maxheight){
if($twin.height() > minheight) {
$textarea.height($twin.height());
} else {
$textarea.height(minheight);
}
}
});
// And this line is to catch the browser paste event
$textarea.bind('input paste',function(e){ setTimeout( update, 250); });
// Run update once when elastic is initialized
update();
});
}
});
})(jQuery);

File diff suppressed because one or more lines are too long

11965
zerobin/static/js/vue.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
</script>
<p class="alert alert-error">
<a class="close" data-dismiss="alert" href="#">×</a>
<a class="close" data-dismiss="alert" href="#" @click.prevent="$event.target.parentNode.remove()">×</a>
<strong class="title">404 Error!</strong>
<span class="message">
Either this paste has expired or this page never existed.
@ -11,30 +11,40 @@
</p>
<p class="file-upload">
<input type="button" class="btn btn-upload" value="Upload File">
<input type="file" class="hide-upload" id="file-upload" >
<input type="button" class="btn btn-upload" :value="isUploading ? 'Uploading...': 'Upload file'"
:disabled="isUploading">
<input type="file" class="hide-upload" id="file-upload" @change="handleUpload($event.target.files)">
</p>
<form class="well" method="post" action="/paste/create">
<p class="paste-option">
<label for="expiration" >Expiration:</label>
<select id="expiration" name="expiration">
<option value="burn_after_reading">Burn after reading</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
</p>
<p>
<div class="progress progress-striped active">
<p class="paste-option">
<label for="expiration">Expiration:</label>
<select id="expiration" name="expiration" v-model="newPaste.expiration">
<option value="burn_after_reading">Burn after reading</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary" @click="encryptAndSendPaste($event)">Submit</button>
</p>
<p>
<div class="progress progress-striped active" v-show="isLoading">
<div class="bar"></div>
</div>
<textarea rows="10" style="width:100%;"
class="input-xlarge"
id="content" name="content"></textarea>
</p>
<textarea rows="10" style="width:100%;" class="input-xlarge" id="content" name="content" autofocus
v-on:keydown.ctrl.enter="encryptAndSendPaste($event)"></textarea>
</p>
<p class="paste-option down" v-if="displayBottomToolBar">
<label for="expiration">Expiration:</label>
<select id="expiration" name="expiration" v-model="newPaste.expiration">
<option value="burn_after_reading">Burn after reading</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary" @click="encryptAndSendPaste($event)">Submit</button>
</p>
</form>
% rebase('base', settings=settings, pastes_count=pastes_count)
% rebase('base', settings=settings, pastes_count=pastes_count)

View File

@ -1,165 +1,180 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>0bin - encrypted pastebin</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description"
content="0bin is a client-side-encrypted
<head>
<meta charset="utf-8">
<title>0bin - encrypted pastebin</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="0bin is a client-side-encrypted
pastebin featuring burn after reading, history, and
a clipboard">
<link rel="shortcut icon" href="/favicon.ico">
<link rel="shortcut icon" href="/favicon.ico">
%if settings.COMPRESSED_STATIC_FILES:
<link href="/static/css/style.min.css?{{ settings.VERSION }}"
rel="stylesheet" />
%else:
<link href="/static/css/prettify.css" rel="stylesheet" />
<link href="/static/css/bootstrap.css" rel="stylesheet">
<link href="/static/css/style.css?{{ settings.VERSION }}"
rel="stylesheet">
%end
%if settings.COMPRESSED_STATIC_FILES:
<link href="/static/css/style.min.css?{{ settings.VERSION }}" rel="stylesheet" />
%else:
<link href="/static/css/prettify.css" rel="stylesheet" />
<link href="/static/css/bootstrap.css" rel="stylesheet">
<link href="/static/css/style.css?{{ settings.VERSION }}" rel="stylesheet">
%end
<!-- Le HTML5 shim, for IE7-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<!-- Le HTML5 shim, for IE7-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
%if settings.COMPRESSED_STATIC_FILES:
<script src="/static/js/main.min.js?{{ settings.VERSION }}"></script>
%else:
<script src="/static/js/jquery-1.7.2.min.js"></script>
<script src="/static/js/sjcl.js"></script>
<script src="/static/js/behavior.js?{{ settings.VERSION }}"></script>
%end
</head>
<script type="text/javascript">
zerobin.max_size = {{ settings.MAX_SIZE }};
</script>
<body>
</head>
<div class="navbar navbar-fixed-top" id="menu-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="/"><span>ø</span>bin<em>.net</em></a>
<div class="nav-collapse">
<ul class="nav">
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse"
data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="/"><span>ø</span>bin<em>.net</em></a>
<div class="nav-collapse">
<ul class="nav">
%for i, entry in enumerate(settings.MENU):
<li
%if not i:
class="active"
%end
>
%if "mailto:" in entry[1]:
<span title="{{ entry[1].replace('mailto:', '').replace('@', '__AT__') }}"
class="email-link" >
{{ entry[0] }}
</span>
%else:
<a href="{{ entry[1] }}">{{ entry[0] }}</a>
%end
</li>
%for i, entry in enumerate(settings.MENU):
<li>
%if "mailto:" in entry[1]:
<a :href="formatEmail('{{ entry[1].replace('mailto:', '').replace('@', '__AT__') }}')" class="email-link">
{{ entry[0] }}
</a>
%else:
<a href="{{ entry[1] }}">{{ entry[0] }}</a>
%end
</ul>
<p class="about pull-right">
"A client side encrypted PasteBin"<br>
<span>All pastes are AES256 encrypted, we cannot know what you paste...</span>
</p>
</div><!--/.nav-collapse -->
</li>
%end
</ul>
<p class="about pull-right">
"A client side encrypted PasteBin"<br>
<span>All pastes are AES256 encrypted, we cannot know what you paste...</span>
</p>
</div>
<!--/.nav-collapse -->
</div>
</div>
</div>
<noscript class="container noscript">
<p>This pastebin uses client-side encryption. Therefore, it needs JavaScript enabled.</p>
<p>It seems like your browser doesn't have JavaScript enable.</p>
<p>Please enable JavaScript for this website or use a JavaScript-capable web browser.</p>
</noscript>
<noscript class="noscript">
<div class="container" id="wrap-content">
<div class="row">
<div class="span2">
<div class="well sidebar-nav">
<ul class="nav nav-list previous-pastes">
<li class="nav-header">Previous pastes</li>
<li class="item local-storage">
<em class="grey">
Your previous pastes will be saved in your browser using
<a href="http://www.w3.org/TR/webstorage/">localStorage</a>.
</em>
</li>
<li class="item no-local-storage">
<em class="grey">
Sorry your browser does not support
<a href="http://www.w3.org/TR/webstorage/">LocalStorage</a>,
We cannot display your previous pastes.
</em>
</li>
</ul>
</div><!--/.well -->
</div><!--/span-->
<div class="container jumbotron">
<h1 class="display-4">This site requires Javascript</h1>
<p class="lead">This pastebin uses client-side encryption, and therefore, it needs JavaScript to work.</p>
<p>It seems like your browser doesn't have JavaScript enabled.</p>
<p>Please enable JavaScript for this website or use a JavaScript-capable web browser.</p>
</div>
<div id='main' class="span10">
{{!base}}
</noscript>
</div><!--/span-->
<div class="container app" id="wrap-content" v-cloak>
<div class="row">
<div class="span2">
<div class="well sidebar-nav">
<ul class="nav nav-list previous-pastes">
<li class="nav-header">Previous pastes</li>
<li class="item local-storage" v-if="previousPastes.length === 0">
<em class="grey">
Your previous pastes will be saved in your browser using
<a href="http://www.w3.org/TR/webstorage/">localStorage</a>.
</em>
</li>
<li class="item no-local-storage">
<em class="grey">
Sorry your browser does not support
<a href="http://www.w3.org/TR/webstorage/">LocalStorage</a>,
We cannot display your previous pastes.
</em>
</li>
<li :class="{item: true, active: paste.isCurrent}" v-for="paste in previousPastes">
<a :href="paste.link" @click="forceLoadPaste(paste.link)">
{% paste.prefix %}{% paste.displayDate %}
</a>
</li>
</ul>
</div>
<!--/.well -->
</div>
<!--/span-->
</div><!--/row-->
<div id='main' class="span10">
<hr>
<footer>
<blockquote>
<p>“Few persons can be made to believe that it is not quite an easy thing to invent a method of secret writing which shall baffle investigation. Yet it may be roundly asserted that human ingenuity cannot concoct a cipher which human ingenuity cannot resolve...”</p>
<p :class="'alert alert-' + msg.type" v-for="msg in messages">
<a class="close" data-dismiss="alert" href="#" @click="$event.target.parentNode.remove()">×</a>
<strong class="title" v-if="msg.title" v-html="msg.title"></strong>
<span class="message" v-html="msg.content"></span>
<a v-if="msg.action.message" href="#"
@click.once.prevent="msg.action.callback($event)">{% msg.action.message %}</a>
</p>
{{!base}}
</div>
<!--/span-->
</div>
<!--/row-->
<hr>
<footer>
<blockquote>
<p>“Few persons can be made to believe that it is not quite an easy thing to invent a method of secret writing
which shall baffle investigation. Yet it may be roundly asserted that human ingenuity cannot concoct a cipher
which human ingenuity cannot resolve...”</p>
<small>Edgar Allan Poe</small>
</blockquote>
%if settings.DISPLAY_COUNTER:
<h4 id="pixels-total" >
<p>ø</p>
<strong>{{ pastes_count }}</strong> <br/>pastes øbinned
</h4>
<h4 id="pixels-total">
<p>ø</p>
<strong>{{ pastes_count }}</strong> <br />pastes øbinned
</h4>
%end
</br>
<p class="greetings span12">
Based on an original idea from
<a href="http://sebsauvage.net/paste/">sebsauvage.net</a><br>
<a href="http://sametmax.com">Sam &amp; Max</a>
</p>
</footer>
<br>
<p class="greetings span12">
Based on an original idea from
<a href="http://sebsauvage.net/paste/">sebsauvage.net</a><br>
<a href="http://sametmax.com">Sam &amp; Max</a>
</p>
</footer>
%if settings.COMPRESSED_STATIC_FILES:
<script src="/static/js/additional.min.js?{{ settings.VERSION }}"></script>
%else:
<script src="/static/js/jquery.elastic.source.js"></script>
<script src="/static/js/lzw.js"></script>
<script src="/static/js/prettify.min.js"></script>
<script src="/static/js/ZeroClipboard.js"></script>
%end
</div>
<!--/wrap-content-->
<p id="alert-template">
<a class="close" data-dismiss="alert" href="#">×</a>
<strong class="title"></strong>
<span class="message"></span>
</p>
</div><!--/wrap-content-->
<script src="/static/js/vue.js"></script>
%if settings.COMPRESSED_STATIC_FILES:
<script src="/static/js/main.min.js?{{ settings.VERSION }}"></script>
%else:
<script src="/static/js/sjcl.js"></script>
<script src="/static/js/behavior.js?{{ settings.VERSION }}"></script>
%end
</body>
<script type="text/javascript">
zerobin.max_size = {{ settings.MAX_SIZE }};
</script>
%if settings.COMPRESSED_STATIC_FILES:
<script src="/static/js/additional.min.js?{{ settings.VERSION }}"></script>
%else:
<script src="/static/js/lzw.js"></script>
<script src="/static/js/prettify.min.js"></script>
%end
</body>
</html>

View File

@ -1,26 +1,37 @@
<p class="file-upload">
<input type="button" class="btn btn-upload" value="Upload File">
<input type="file" class="hide-upload" id="file-upload" >
<p class="file-upload" v-if="support.fileUpload">
<input type="button" class="btn btn-upload" value="Upload File" :value="isUploading ? 'Uploading...': 'Upload file'"
:disabled="isUploading">
<input type="file" class="hide-upload" id="file-upload" @change="handleUpload($event.target.files)">
</p>
<form class="well" method="post" action="/paste/create">
<p class="paste-option">
<label for="expiration" >Expiration:</label>
<select id="expiration" name="expiration">
<label for="expiration">Expiration:</label>
<select id="expiration" name="expiration" v-model="newPaste.expiration">
<option value="burn_after_reading">Burn after reading</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
<button type="submit" class="btn btn-primary" @click="encryptAndSendPaste($event)">Submit</button>
</p>
<p>
<div class="progress progress-striped active">
<div class="bar"></div>
</div>
<textarea rows="10" style="width:100%;"
class="input-xlarge"
id="content" name="content"></textarea>
<div class="progress progress-striped active" v-show="isLoading">
<div class="bar"></div>
</div>
<textarea rows="10" style="width:100%" class="input-xlarge" id="content" name="content" autofocus
v-on:keydown.ctrl.enter="encryptAndSendPaste($event)"></textarea>
</p>
<p class="paste-option down" v-if="displayBottomToolBar">
<label for="expiration">Expiration:</label>
<select id="expiration" name="expiration" v-model="newPaste.expiration">
<option value="burn_after_reading">Burn after reading</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary" @click="encryptAndSendPaste($event)">Submit</button>
</p>
</form>

View File

@ -1,87 +1,108 @@
%if "burn_after_reading" in str(paste.expiration):
%if keep_alive:
<p class="alert alert-info">
<a class="close" data-dismiss="alert" href="#">×</a>
<strong class="title">Ok!</strong>
<span class="message">
This paste will be deleted the next time it is read.
</span>
</p>
%else:
<p class="alert">
<a class="close" data-dismiss="alert" href="#">×</a>
<strong class="title">Warning!</strong>
<span class="message">
This paste has self-destructed. If you close this window,
there is no way to recover it.
</span>
</p>
%end
%if keep_alive:
<p class="alert alert-info">
<a class="close" data-dismiss="alert" href="#" @click="$event.target.parentNode.remove()">×</a>
<strong class="title">Ok!</strong>
<span class="message">
This paste will be deleted the next time it is read.
</span>
</p>
%else:
<p class="alert">
<a class="close" data-dismiss="alert" href="#" @click="$event.target.parentNode.remove()">×</a>
<strong class="title">Warning!</strong>
<span class="message">
This paste has self-destructed. If you close this window,
there is no way to recover it.
</span>
</p>
%end
%end
<div class="well paste-form">
<form action="/" method="get" accept-charset="utf-8">
<p class="lnk-option">
<a id="clip-button" href="#">Copy To Clipboard</a> |
<a id="short-url" href="#">Get short url</a> |
<a id="email-link" href="#">Email this</a>
<form action="/" method="get" accept-charset="utf-8">
<p class="lnk-option">
<a id="clip-button" v-if="support.clipboard" href="#" @click.prevent="copyToClipboard()">Copy To Clipboard</a> |
<span class="paste-option btn-group top">
<button class="btn btn-clone"><i class="icon-camera"></i>&nbsp;Clone</button>
<button class="btn">New Paste</button>
</span>
</p>
<a id="email-link" href="#" @click="handleSendByEmail($event)">Email this</a>
<div class="progress progress-striped active">
<div class="bar"></div>
</div>
<span class="paste-option btn-group top">
<button class="btn btn-clone" @click.prevent="handleClone()"><i class="icon-camera"></i>&nbsp;Clone</button>
<button class="btn" v-if="downloadLink.url">
<a :href="downloadLink.url" :download="downloadLink.name"><i class="icon-download"></i> Download</a>
</button>
%expiration = paste.humanized_expiration
%if expiration:
<p id="expiration-tag">Expire {{ expiration }}</p>
%end
<p>
<pre id="paste-content" class="prettyprint">
<button class="btn">New Paste</button>
</span>
</p>
<div class="progress progress-striped active" v-show="isLoading">
<div class="bar"></div>
</div>
%expiration = paste.humanized_expiration
%if expiration:
<p id="expiration-tag">Expire {{ expiration }}</p>
%end
<p>
<pre id="paste-content" class="prettyprint">
<code>
{{ paste.content }}
</code>
</pre>
</p>
</p>
<p class="paste-option btn-group bottom">
<button class="btn btn-clone"><i class="icon-camera"></i>&nbsp;Clone</button>
<button class="btn">New Paste</button>
</p>
<p class="paste-option btn-group bottom">
<button class="btn btn-clone" @click.prevent="handleClone()"><i class="icon-camera"></i>&nbsp;Clone</button>
</form>
<button class="btn" v-if="downloadLink.url">
<a :href="downloadLink.url" :download="downloadLink.name"><i class="icon-download"></i> Download</a>
</button>
<button class="btn">New Paste</button>
</p>
</form>
</div>
<!-- For cloning -->
<div class="submit-form clone">
<form class="well" method="post" action="/paste/create">
<p class="paste-option">
<label for="expiration" >Expiration:</label>
<select id="expiration" name="expiration">
<label for="expiration">Expiration:</label>
<select id="expiration" name="expiration" v-model="newPaste.expiration">
<option value="burn_after_reading">Burn after reading</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
<button class="btn btn-danger">Cancel clone</button>
<button type="submit" class="btn btn-primary" @click="encryptAndSendPaste($event)">Submit</button>
<button class="btn btn-danger" @click.prevent="handleCancelClone()">Cancel clone</button>
</p>
<div>
<div class="progress progress-striped active">
<div class="bar"></div>
</div>
<textarea rows="10" style="width:100%;"
class="input-xlarge"
id="content" name="content"></textarea>
<div class="progress progress-striped active" v-show="isLoading">
<div class="bar"></div>
</div>
<textarea rows="10" style="width:100%;" class="input-xlarge" id="content" name="content" autofocus
v-on:keydown.ctrl.enter="encryptAndSendPaste($event)"></textarea>
</div>
<p class="paste-option down" v-if="displayBottomToolBar">
<label for="expiration">Expiration:</label>
<select id="expiration" name="expiration" v-model="newPaste.expiration">
<option value="burn_after_reading">Burn after reading</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary" @click="encryptAndSendPaste($event)">Submit</button>
</p>
</form>
</div>
% rebase("base", settings=settings, pastes_count=pastes_count)