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

1032 lines
31 KiB
JavaScript
Raw Normal View History

2020-08-11 17:37:03 +03:00
/*global sjcl:true, jQuery:true, lzw:true, zerobin:true, prettyPrint:true */
2020-08-11 12:55:29 +03:00
/*
2020-08-11 17:37:03 +03:00
This file has been migrated away from jQuery, to Vue. Because of the way
the code base used to be, a lot of the operations are still using imperative
DOM manipulation instead of the Vue declarative style. We haven't had the
time to rewrite it completly and it's a bit of a mixed bag at the moment.
2020-08-11 12:55:29 +03:00
*/
2020-08-11 12:55:29 +03:00
/* Start random number generator seeding ASAP */
sjcl.random.startCollectors();
2020-08-11 17:37:03 +03:00
// Vue template syntax conflicts with bottle template syntax
2020-08-11 12:55:29 +03:00
Vue.options.delimiters = ['{%', '%}'];
// Force focus for textarea (firefox hack)
setTimeout(function () {
2020-08-14 19:18:17 +03:00
document.getElementById('content').focus();
2020-08-11 12:55:29 +03:00
}, 100)
2020-08-14 19:18:17 +03:00
var app = new Vue({
2020-08-11 12:55:29 +03:00
2020-08-12 12:00:41 +03:00
el: '#app',
2020-08-11 12:55:29 +03:00
data: {
previousPastes: [],
displayBottomToolBar: false,
2020-08-15 14:27:51 +03:00
openPreviousPastesMenu: false,
2020-08-13 17:53:17 +03:00
readerMode: false,
2020-08-11 12:55:29 +03:00
isUploading: false,
2020-08-15 11:02:57 +03:00
btcCopied: false,
2020-08-11 17:37:03 +03:00
currentPaste: {
ownerKey: '',
2020-08-12 15:02:13 +03:00
id: '',
type: '',
content: '',
downloadLink: {},
2020-08-14 16:08:55 +03:00
title: '',
2020-08-14 17:41:45 +03:00
btcTipAddress: ''
2020-08-11 17:37:03 +03:00
},
2020-08-11 12:55:29 +03:00
newPaste: {
expiration: '1_day',
content: '',
2020-08-14 16:08:55 +03:00
title: '',
2020-08-14 17:41:45 +03:00
btcTipAddress: ''
},
2020-08-11 12:55:29 +03:00
messages: [],
/** Check for browser support of the named featured. Store the result
2020-08-11 12:55:29 +03:00
and add a class to the html tag with the result */
support: {
2020-08-11 12:55:29 +03:00
2020-08-12 15:02:13 +03:00
clipboard: !!(isSecureContext && navigator.clipboard && navigator.clipboard.writeText),
2020-08-11 12:55:29 +03:00
2020-08-14 12:18:59 +03:00
URLSearchParams: !!window.URLSearchParams,
localStorage: (function () {
2020-08-11 12:55:29 +03:00
var val = !!(localStorage);
document.querySelector('html').classList.add((val ? '' : 'no-') + 'local-storage');
return val;
})(),
history: (function () {
2020-08-11 12:55:29 +03:00
var val = !!(window.history && history.pushState);
document.querySelector('html').classList.add((val ? '' : 'no-') + 'history');
return val;
})(),
fileUpload: (function () {
var w = window;
2020-08-11 12:55:29 +03:00
var val = !!(w.File && w.FileReader && w.FileList && w.Blob);
document.querySelector('html').classList.add((val ? '' : 'no-') + 'file-upload');
return val;
})()
},
2020-08-11 12:55:29 +03:00
isLoading: false
},
methods: {
2020-08-12 12:00:41 +03:00
2020-08-13 17:53:17 +03:00
toggleReaderMode: function () {
if (!this.readerMode) {
this.messages = [];
2020-08-14 12:18:59 +03:00
if (this.support.URLSearchParams) {
2020-08-14 19:18:17 +03:00
var searchParams = new URLSearchParams(window.location.search);
2020-08-14 12:18:59 +03:00
searchParams.set('readerMode', 1);
window.location.search = searchParams.toString();
}
} else {
if (this.support.URLSearchParams) {
var searchParams = new URLSearchParams(window.location.search);
searchParams.delete('readerMode');
window.location.search = searchParams.toString();
}
2020-08-13 17:53:17 +03:00
}
this.readerMode = !this.readerMode;
},
increaseFontSize: function (amount) {
2020-08-14 19:18:17 +03:00
var readableModeContent = document.getElementById('readable-paste-content');
2020-08-13 17:53:17 +03:00
2020-08-14 19:18:17 +03:00
var fontSize = window.getComputedStyle(readableModeContent, null).getPropertyValue('font-size');
2020-08-13 17:53:17 +03:00
amount = amount || 5;
readableModeContent.style.fontSize = (parseFloat(fontSize) + amount) + "px";
},
decreaseFontSize: function () {
this.increaseFontSize(-5);
},
2020-08-14 19:18:17 +03:00
formatEmail: function (email) {
2020-08-12 12:00:41 +03:00
return "mailto:" + email.replace('__AT__', '@');
},
2020-08-14 19:18:17 +03:00
forceLoad: function (link) {
2020-08-11 12:55:29 +03:00
window.location = link;
window.location.reload();
},
2020-08-14 16:08:55 +03:00
handleClone: function () {
2020-08-11 12:55:29 +03:00
document.querySelector('.submit-form').style.display = "inherit";
document.querySelector('.paste-form').style.display = "none";
2020-08-14 19:18:17 +03:00
var title = document.querySelector('h1');
2020-08-14 17:41:45 +03:00
if (title) {
title.style.display = "none";
}
2020-08-14 19:18:17 +03:00
var content = document.getElementById('content');
2020-08-11 12:55:29 +03:00
content.value = zerobin.getPasteContent();
content.dispatchEvent(new Event('change'));
2020-08-14 16:08:55 +03:00
this.newPaste.title = this.currentPaste.title;
2020-08-14 17:41:45 +03:00
this.newPaste.btcTipAddress = this.currentPaste.btcTipAddress;
},
2020-08-14 19:18:17 +03:00
handleCancelClone: function () {
2020-08-11 12:55:29 +03:00
document.querySelector('.submit-form').style.display = "none";
document.querySelector('.paste-form').style.display = "inherit";
2020-08-14 16:08:55 +03:00
document.querySelector('h1').style.display = "inherit";
},
2012-05-12 12:15:09 +04:00
2020-08-14 19:18:17 +03:00
handleUpload: function (files) {
2020-08-11 12:55:29 +03:00
try {
app.isUploading = true;
zerobin.upload(files);
} catch (e) {
zerobin.message('danger', 'Could no upload the file', 'Error');
}
2020-08-11 12:55:29 +03:00
app.isUploading = false;
},
2020-08-14 19:18:17 +03:00
handleForceColoration: function (e) {
var content = document.getElementById('paste-content');
2020-08-11 12:55:29 +03:00
content.classList.add('linenums');
e.target.innerHTML = 'Applying coloration';
prettyPrint();
2020-08-11 17:37:03 +03:00
e.target.parentNode.remove()
},
2020-08-14 19:18:17 +03:00
handleSendByEmail: function (e) {
2020-08-12 12:21:18 +03:00
window.location = 'mailto:friend@example.com?body=' + window.location.toString();
},
2020-08-14 19:18:17 +03:00
handleDeletePaste: function () {
2020-08-11 17:37:03 +03:00
if (window.confirm("Delete this paste?")) {
app.isLoading = true;
bar.set('Deleting paste...', '50%');
fetch('/paste/' + app.currentPaste.id, {
method: "DELETE",
body: new URLSearchParams({
"owner_key": app.currentPaste.ownerKey
})
}).then(function (response) {
if (response.ok) {
window.location = "/";
2020-08-11 17:37:03 +03:00
} else {
2020-08-14 19:18:17 +03:00
form.forEach(function (node) {
node.disabled = false;
});
2020-08-11 17:37:03 +03:00
app.isLoading = false
zerobin.message(
'danger',
2020-08-11 17:37:03 +03:00
'Paste could not be deleted. Please try again later.',
'Error');
}
app.isLoading = false;
}).catch(function (error) {
zerobin.message(
'danger',
2020-08-11 17:37:03 +03:00
'Paste could not be delete. Please try again later.',
'Error');
app.isLoading = false;
});
}
},
2020-08-14 19:18:17 +03:00
copyToClipboard: function () {
2020-08-11 12:55:29 +03:00
var pasteContent = zerobin.getPasteContent();
2020-08-14 19:18:17 +03:00
var promise = navigator.clipboard.writeText(pasteContent);
2020-08-11 12:55:29 +03:00
promise.then(function () {
zerobin.message('primary', 'The paste is now in your clipboard', '', true);
2020-08-11 12:55:29 +03:00
}, function (err) {
zerobin.message('danger', 'The paste could not be copied', '', true);
2020-08-11 12:55:29 +03:00
});
2020-08-11 12:55:29 +03:00
},
2012-04-26 13:38:55 +04:00
copyBTCAdressToClipboard: function () {
2020-08-15 11:02:57 +03:00
var promise = navigator.clipboard.writeText(this.currentPaste.btcTipAddress);
app.btcCopied = true;
promise.then(function () {
if (app.btcCopied) {
clearTimeout(app.btcCopied);
}
app.btcCopied = setTimeout(function () {
app.btcCopied = false;
}, 3000)
}, function (err) {
zerobin.message('danger', 'The BTC addresse could not be copied', '', true);
});
},
2020-08-15 13:05:22 +03:00
compressImage: function (base64) {
var canvas = document.createElement('canvas')
var img = document.createElement('img')
return new Promise(function (resolve, reject) {
img.onload = function () {
var width = img.width;
var height = img.height;
var biggest = width > height ? width : height;
var maxHeight = height;
var maxWidth = width;
if (width > height) {
if (width > maxWidth) {
height = Math.round((height *= maxWidth / width));
width = maxWidth;
}
} else {
if (height > maxHeight) {
width = Math.round((width *= maxHeight / height));
height = maxHeight;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);
2020-08-15 13:08:04 +03:00
resolve(canvas.toDataURL('image/jpeg', 0.7));
2020-08-15 13:05:22 +03:00
}
img.onerror = function (err) {
reject(err);
}
img.src = base64;
})
},
/**
2020-08-11 12:55:29 +03:00
On the create paste page:
On click on the send button, compress and encrypt data before
posting it using ajax. Then redirect to the address of the
newly created paste, adding the key in the hash.
*/
2020-08-14 19:18:17 +03:00
encryptAndSendPaste: function () {
2012-04-26 13:38:55 +04:00
2020-08-11 12:55:29 +03:00
var paste = document.querySelector('textarea').value;
2012-04-26 13:38:55 +04:00
if (paste.trim()) {
2020-08-11 12:55:29 +03:00
var form = document.querySelectorAll('input, textarea, select, button');
2020-08-14 19:18:17 +03:00
form.forEach(function (node) {
node.disabled = true;
});
// set up progress bar
var bar = zerobin.progressBar('form.well .progress');
2020-08-11 12:55:29 +03:00
app.isLoading = true;
bar.set('Converting paste to bits...', '25%');
/* Encode, compress, encrypt and send the paste then redirect the user
2020-08-11 12:55:29 +03:00
to the new paste. We ensure a loading animation is updated
during the process by passing callbacks.
*/
try {
2014-06-20 11:16:17 +04:00
var key = zerobin.makeKey(256);
2020-08-15 13:05:22 +03:00
var promise = new Promise(function (resolve, reject) {
resolve(paste);
}); // noop to avoid branching
if (paste.indexOf('data:image') == 0) {
promise = app.compressImage(paste);
}
promise.then(function (base64) {
zerobin.encrypt(key, base64,
function () {
bar.set('Encoding to base64...', '45%')
},
function () {
bar.set('Compressing...', '65%')
},
function () {
bar.set('Encrypting...', '85%')
},
/* This block deals with sending the data, redirection or error handling */
function (content) {
bar.set('Sending...', '95%');
var data = {
content: content,
expiration: app.newPaste.expiration,
title: app.newPaste.title,
btcTipAddress: app.newPaste.btcTipAddress
};
var sizebytes = zerobin.count(JSON.stringify(data));
var oversized = sizebytes > zerobin.max_size; // 100kb - the others header information
var readableFsize = Math.round(sizebytes / 1024);
var readableMaxsize = Math.round(zerobin.max_size / 1024);
if (oversized) {
app.isLoading = false
form.forEach(function (node) {
node.disabled = false;
});
zerobin.message('danger', ('The file was <strong class="file-size">' + readableFsize +
'</strong>KB after encryption. You have reached the maximum size limit of ' + readableMaxsize + 'KB.'),
'Warning!', true);
return;
}
2012-04-30 00:15:11 +04:00
2020-08-15 13:05:22 +03:00
fetch('/paste/create', {
method: "POST",
body: new URLSearchParams(data)
}).then(function (response) {
if (response.ok) {
bar.set('Redirecting to new paste...', '100%');
response.json().then(function (data) {
if (data.status === 'error') {
zerobin.message('danger', data.message, 'Error');
form.forEach(function (node) {
node.disabled = false;
});
app.isLoading = false;
} else {
if (app.support.localStorage) {
zerobin.storePaste('/paste/' + data.paste + "?owner_key=" + data.owner_key + '#' + key);
}
window.location = ('/paste/' + data.paste + '#' + key);
}
})
2020-08-11 12:55:29 +03:00
2020-08-15 13:05:22 +03:00
} else {
2020-08-14 19:18:17 +03:00
form.forEach(function (node) {
2020-08-15 13:05:22 +03:00
node.disabled = false
2020-08-14 19:18:17 +03:00
});
app.isLoading = false;
2020-08-15 13:05:22 +03:00
zerobin.message(
'danger',
'Paste could not be saved. Please try again later.',
'Error');
2020-08-11 12:55:29 +03:00
}
2020-08-15 13:05:22 +03:00
}).catch(function (error) {
form.forEach(function (node) {
node.disabled = false;
});
app.isLoading = false;
zerobin.message(
'danger',
'Paste could not be saved. Please try again later.',
'Error');
2020-08-14 19:18:17 +03:00
});
2020-08-15 13:05:22 +03:00
})
}),
function (err) {
debugger;
form.forEach(function (node) {
node.disabled = false;
2020-08-11 12:55:29 +03:00
});
2020-08-15 13:05:22 +03:00
app.isLoading = false;
zerobin.message('danger', 'Paste could not be encrypted. Aborting.',
'Error');
};
2020-08-11 12:55:29 +03:00
} catch (err) {
2020-08-14 19:18:17 +03:00
form.forEach(function (node) {
node.disabled = false;
});
app.isLoading = false;
zerobin.message('danger', 'Paste could not be encrypted. Aborting.',
'Error');
}
}
2020-08-11 12:55:29 +03:00
}
}
})
2012-04-24 22:15:38 +04:00
2020-08-11 17:37:03 +03:00
/****************************
**** 0bin utilities ****
****************************/
2020-08-11 12:55:29 +03:00
window.zerobin = {
/** Base64 + compress + encrypt, with callbacks before each operation,
and all of them are executed in a timed continuation to give
a change to the UI to respond.
*/
version: '0.1.1',
encrypt: function (key, content, toBase64Callback,
compressCallback, encryptCallback, doneCallback) {
setTimeout(function () {
content = sjcl.codec.utf8String.toBits(content);
if (toBase64Callback) {
toBase64Callback();
}
setTimeout(function () {
content = sjcl.codec.base64.fromBits(content);
if (compressCallback) {
compressCallback();
}
2020-08-11 12:55:29 +03:00
setTimeout(function () {
2020-08-11 12:55:29 +03:00
// content = lzw.compress(content); // Create a bug with JPG
if (encryptCallback) {
encryptCallback();
}
2020-08-11 12:55:29 +03:00
setTimeout(function () {
try {
content = sjcl.encrypt(key, content);
} catch (e) {
2020-08-14 19:18:17 +03:00
document.querySelectorAll('input, textarea, select, button').forEach(function (node) {
node.disabled = true
});
2020-08-11 12:55:29 +03:00
app.isLoading = false;
zerobin.message('danger', 'Paste could not be encrypted. Aborting.',
2020-08-11 12:55:29 +03:00
'Error');
}
if (doneCallback) {
doneCallback(content);
}
2020-08-12 12:15:01 +03:00
}, 50);
2020-08-12 12:15:01 +03:00
}, 50);
2012-04-28 21:57:18 +04:00
2020-08-12 12:15:01 +03:00
}, 50);
2020-08-12 12:15:01 +03:00
}, 50);
2020-08-11 12:55:29 +03:00
},
2020-08-11 12:55:29 +03:00
/** Base64 decoding + uncompress + decrypt, with callbacks before each operation,
and all of them are executed in a timed continuation to give
a change to the UI to respond.
This is where using a library to fake synchronicity could start to be
useful, this code is starting be difficult to read. If anyone read this
and got a suggestion, by all means, speak your mind.
*/
decrypt: function (key, content, errorCallback, uncompressCallback,
fromBase64Callback, toStringCallback, doneCallback) {
2020-08-11 12:55:29 +03:00
/* Decrypt */
setTimeout(function () {
try {
content = sjcl.decrypt(key, content);
if (uncompressCallback) {
uncompressCallback();
}
2020-08-11 12:55:29 +03:00
/* Decompress */
setTimeout(function () {
2020-08-11 12:55:29 +03:00
try {
2020-08-14 19:18:17 +03:00
2020-08-11 12:55:29 +03:00
if (fromBase64Callback) {
fromBase64Callback();
}
2020-08-11 12:55:29 +03:00
/* From base 64 to bits */
setTimeout(function () {
try {
content = sjcl.codec.base64.toBits(content);
if (toStringCallback) {
toStringCallback();
}
2020-08-11 12:55:29 +03:00
/* From bits to string */
setTimeout(function () {
try {
content = sjcl.codec.utf8String.fromBits(content);
if (doneCallback) {
doneCallback(content);
}
} catch (err) {
2020-08-14 12:18:59 +03:00
debugger;
2020-08-11 12:55:29 +03:00
errorCallback(err);
}
2020-08-12 12:15:01 +03:00
}, 50); /* "End of from bits to string" */
2012-04-28 21:57:18 +04:00
2020-08-11 12:55:29 +03:00
} catch (err) {
errorCallback(err);
}
2012-05-06 15:54:57 +04:00
2020-08-12 12:15:01 +03:00
}, 50); /* End of "from base 64 to bits" */
2020-08-11 12:55:29 +03:00
} catch (err) {
errorCallback(err);
}
2020-08-12 12:15:01 +03:00
}, 50); /* End of "decompress" */
2012-04-28 21:57:18 +04:00
2020-08-11 12:55:29 +03:00
} catch (err) {
errorCallback(err);
}
2020-08-12 12:15:01 +03:00
}, 50); /* End of "decrypt" */
2020-08-11 12:55:29 +03:00
},
/** Create a random base64-like string long enought to be suitable as
an encryption key */
makeKey: function (entropy) {
entropy = Math.ceil(entropy / 6) * 6; /* non-6-multiple produces same-length base64 */
var key = sjcl.bitArray.clamp(
sjcl.random.randomWords(Math.ceil(entropy / 32), 0), entropy);
return sjcl.codec.base64.fromBits(key, 0).replace(/\=+$/, '').replace(/\//, '-');
},
getFormatedDate: function (date) {
date = date || new Date();
return ((date.getMonth() + 1) + '-' + date.getDate() + '-' + date.getFullYear());
},
getFormatedTime: function (date) {
date = date || new Date();
var h = date.getHours(),
m = date.getMinutes(),
s = date.getSeconds();
if (h < 10) {
h = "0" + h;
}
if (m < 10) {
m = "0" + m;
}
if (s < 10) {
s = "0" + s;
}
return h + ":" + m + ":" + s;
},
numOrdA: function (a, b) {
return (a - b);
},
/** Return a reverse sorted list of all the keys in local storage that
are prefixed with with the passed version (default being this lib
version) */
2020-08-11 17:37:03 +03:00
getLocalStorageURLKeys: function () {
var version = 'zerobinV' + zerobin.version;
2020-08-11 12:55:29 +03:00
var keys = [];
for (var key in localStorage) {
2020-08-11 17:37:03 +03:00
if (key.indexOf(version) !== -1 && key.indexOf("owner_key") === -1) {
2020-08-11 12:55:29 +03:00
keys.push(key);
}
}
keys.sort();
keys.reverse();
return keys;
},
2012-04-28 21:57:18 +04:00
2020-08-11 12:55:29 +03:00
/** Store the paste of a URL in local storate, with a storage format
version prefix and the paste date as the key */
storePaste: function (url, date) {
2020-08-11 12:55:29 +03:00
date = date || new Date();
date = (date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + zerobin.getFormatedTime(date));
2020-08-11 17:37:03 +03:00
var keys = zerobin.getLocalStorageURLKeys();
2020-08-11 12:55:29 +03:00
if (localStorage.length > 19) {
void localStorage.removeItem(keys[19]);
}
2012-04-28 15:25:43 +04:00
2020-08-11 12:55:29 +03:00
localStorage.setItem('zerobinV' + zerobin.version + "#" + date, url);
2020-08-11 17:37:03 +03:00
localStorage.setItem('zerobinV' + zerobin.version + "#" + zerobin.getPasteId(url) + "#owner_key", zerobin.getPasteOwnerKey(url));
2020-08-11 12:55:29 +03:00
},
2020-08-11 12:55:29 +03:00
/** Return a list of the previous paste url with the creation date
If the paste is from today, date format should be "at hh:ss",
else it should be "the mm-dd-yyy"
*/
getPreviousPastes: function () {
2020-08-11 17:37:03 +03:00
var keys = zerobin.getLocalStorageURLKeys(),
2020-08-11 12:55:29 +03:00
today = zerobin.getFormatedDate();
return keys.map(function (key, i) {
var pasteDateTime = key.replace(/^[^#]+#/, '');
var displayDate = pasteDateTime.match(/^(\d+)-(\d+)-(\d+)\s/);
displayDate = displayDate[2] + '-' + displayDate[3] + '-' + displayDate[1];
var prefix = 'the ';
if (displayDate === today) {
displayDate = pasteDateTime.split(' ')[1];
prefix = 'at ';
}
2020-08-14 19:18:17 +03:00
var link = localStorage.getItem(key);
2020-08-11 17:37:03 +03:00
2020-08-11 12:55:29 +03:00
return {
displayDate: displayDate,
prefix: prefix,
2020-08-11 17:37:03 +03:00
// The owner key is stored in the URL, but we don't want the user
// to see it
link: link.replace(/\?[^#]+#/, '#'),
isCurrent: link.replace(/\?[^?]+/, '') === window.location.pathname
2020-08-11 12:55:29 +03:00
};
});
2020-08-11 12:55:29 +03:00
},
2020-08-11 12:55:29 +03:00
/** Return a link object with the URL as href so you can extract host,
protocol, hash, etc.
2012-04-28 21:58:30 +04:00
2020-08-11 12:55:29 +03:00
This function use a closure to store a <div> parent for the <a>
because IE requires the link be processed by it's HTML parser
for the URL to be parsed. */
parseUrl: (function () {
2012-04-28 21:55:00 +04:00
2020-08-11 12:55:29 +03:00
var div = document.createElement('div');
div.innerHTML = "<a></a>";
2012-04-28 21:55:00 +04:00
2020-08-11 12:55:29 +03:00
return function (url) {
div.firstChild.href = url;
div.innerHTML = div.innerHTML;
return div.firstChild;
};
2012-04-29 19:36:26 +04:00
2020-08-11 12:55:29 +03:00
})(),
2012-04-30 00:15:11 +04:00
2020-08-11 12:55:29 +03:00
getPasteId: function (url) {
var loc = url ? zerobin.parseUrl(url) : window.location;
return loc.pathname.replace(/\/|paste/g, '');
},
2012-04-29 19:36:26 +04:00
2020-08-11 17:37:03 +03:00
getPasteOwnerKey: function (url) {
var loc = url ? zerobin.parseUrl(url) : window.location;
return (new URLSearchParams(loc.search)).get("owner_key");
},
2020-08-11 12:55:29 +03:00
getPasteKey: function (url) {
var loc = url ? zerobin.parseUrl(url) : window.location;
return loc.hash.replace('#', '').replace(/(\?|&).*$/, '');
},
2020-08-11 12:55:29 +03:00
/** Return the paste content stripted from any code coloration */
getPasteContent: function () {
var copy = '';
2020-08-14 19:18:17 +03:00
document.querySelectorAll("#paste-content li").forEach(function (node) {
2020-08-11 12:55:29 +03:00
copy = copy + node.textContent.replace(/[\u00a0]+/g, ' ') + '\n';
2020-08-14 19:18:17 +03:00
});
2020-08-11 12:55:29 +03:00
if (copy === '') {
copy = document.querySelector("#paste-content").textContent;
}
return copy;
},
/** Return an approximate estimate of the number of bytes in a text */
count: function (text, options) {
// Set option defaults
var crlf = /(\r?\n|\r)/g;
var whitespace = /(\r?\n|\r|\s+)/g;
options = options || {};
options.lineBreaks = options.lineBreaks || 1;
var length = text.length,
nonAscii = length - text.replace(/[\u0100-\uFFFF]/g, '').length,
lineBreaks = length - text.replace(crlf, '').length;
return length + nonAscii + Math.max(0, options.lineBreaks * (lineBreaks - 1));
},
/** Create a message, style it and insert it in the alert box */
message: function (type, message, title, flush, callback, action) {
window.scrollTo(0, 0);
if (flush) {
2020-08-14 19:18:17 +03:00
app.messages = app.messages.filter(function (msg) {
2020-08-11 12:55:29 +03:00
msg.type !== type
});
}
app.messages.push({
title: title,
content: message,
type: type,
2020-08-11 17:37:03 +03:00
action: action || {},
2020-08-11 12:55:29 +03:00
});
2020-08-14 19:18:17 +03:00
callback && callback();
2020-08-11 12:55:29 +03:00
},
/** Return a progress bar object */
progressBar: function (selector) {
var container = document.querySelector(selector);
var bar = {
container: container,
elem: container.childNodes[0]
};
bar.set = function (text, rate) {
bar.elem.innerHTML = text;
bar.elem.style.width = rate;
};
return bar;
},
/** Return an integer ranking the probability this text is any kind of
source code. */
isCode: function (text) {
var code_chars = /[A-Z]{3}[A-Z]+|\.[a-z]|[=:<>{}\[\]$_'"&]| {2}|\t/g;
var comments = /(:?\/\*|<!--)(:?.|\n)*?(:?\*\/|-->)|(\/\/|#)(.*?)\n/g;
var formating = /[-*=_+]{4,}/;
var total = 0;
var size = 0;
var m = text.match(comments);
if (m) {
total += text.match(comments).length;
}
text = text.replace(comments, '');
text.replace(formating, '');
text = text.split('\n');
for (var i = 0; i < text.length; i++) {
var line = text[i];
size += line.length;
var match = line.replace(formating, '').match(code_chars);
if (match) {
total += match.length;
}
}
2020-08-12 12:34:33 +03:00
return total * 1000 / size;
2020-08-11 12:55:29 +03:00
},
ignoreDrag: function (e) {
e.stopPropagation();
e.preventDefault();
},
handleDrop: function (e) {
e.preventDefault();
zerobin.upload(e.dataTransfer.files);
document.getElementById("content").classList.remove("hover");
},
2020-08-13 19:14:19 +03:00
handlePaste: function (e) {
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") === 0) {
e.preventDefault()
return zerobin.upload([items[i].getAsFile()]);
}
}
},
2020-08-11 12:55:29 +03:00
handleDragOver: function (e) {
zerobin.ignoreDrag(e);
document.getElementById("content").classList.add('hover');
},
handleDragLeave: function (e) {
document.getElementById("content").classList.remove("hover");
},
upload: function (files) {
2020-08-14 19:18:17 +03:00
var content = document.getElementById('content');
2020-08-13 19:14:19 +03:00
var currentFile = files[0];
2020-08-11 12:55:29 +03:00
var reader = new FileReader();
2020-08-13 19:14:19 +03:00
if (currentFile.type.indexOf('image') == 0) {
2020-08-11 12:55:29 +03:00
reader.onload = function (event) {
var image = new Image();
image.src = event.target.result;
2020-08-13 20:04:57 +03:00
content.value = event.target.result
2020-08-11 12:55:29 +03:00
image.onload = function () {
app.messages = []
var previousImage = document.querySelector('.paste-wrapper');
if (previousImage) {
previousImage.remove();
}
2020-08-13 19:14:19 +03:00
var imgWrapper = document.createElement('div');
imgWrapper.classList.add('paste-wrapper');
imgWrapper.appendChild(image)
2020-08-11 12:55:29 +03:00
content.style.display = "none";
2020-08-13 19:14:19 +03:00
content.after(imgWrapper);
2020-08-11 12:55:29 +03:00
}
}
2020-08-13 19:14:19 +03:00
reader.readAsDataURL(currentFile);
2020-08-11 12:55:29 +03:00
} else {
reader.onload = function (event) {
content.value = event.target.result
content.dispatchEvent(new Event('change'));
};
2020-08-13 19:14:19 +03:00
reader.readAsText(currentFile);
}
2020-08-11 12:55:29 +03:00
}
};
2012-04-29 19:36:26 +04:00
2020-08-11 12:55:29 +03:00
/**
DECRYPTION:
On the display paste page, decrypt and decompress the paste content,
add syntax coloration then setup the copy to clipboard button.
Also calculate and set the paste visual hash.
*/
2012-04-29 19:36:26 +04:00
2020-08-14 19:18:17 +03:00
var pasteContent = document.querySelector('#paste-content');
var content = '';
2012-04-28 21:58:30 +04:00
2020-08-11 12:55:29 +03:00
if (pasteContent) {
content = pasteContent.textContent.trim();
2020-08-11 17:37:03 +03:00
app.currentPaste.id = zerobin.getPasteId(window.location);
2020-08-11 12:55:29 +03:00
}
2012-04-28 21:55:00 +04:00
2020-08-11 12:55:29 +03:00
var key = zerobin.getPasteKey();
var error = false;
2012-04-28 21:55:00 +04:00
2020-08-11 12:55:29 +03:00
if (content && key) {
2012-04-29 19:36:26 +04:00
2020-08-11 12:55:29 +03:00
var form = document.querySelectorAll('input, textarea, select, button');
2020-08-14 19:18:17 +03:00
form.forEach(function (node) {
node.disabled = true;
});
2020-08-11 12:55:29 +03:00
var bar = zerobin.progressBar('.well form .progress');
app.isLoading = true;
bar.set('Decrypting paste...', '25%');
2020-08-11 12:55:29 +03:00
zerobin.decrypt(key, content,
2012-04-29 19:36:26 +04:00
2020-08-11 12:55:29 +03:00
/* On error*/
function () {
app.isLoading = false;
zerobin.message('danger', 'Could not decrypt data (Wrong key ?)', 'Error');
2020-08-11 12:55:29 +03:00
},
2012-04-29 19:36:26 +04:00
2020-08-11 12:55:29 +03:00
/* Update progress bar */
2020-08-14 19:18:17 +03:00
function () {
bar.set('Decompressing...', '45%');
},
function () {
bar.set('Base64 decoding...', '65%');
},
function () {
bar.set('From bits to string...', '85%');
},
2020-08-11 12:55:29 +03:00
/* When done */
function (content) {
2020-08-14 19:18:17 +03:00
var readerMode = false;
2020-08-14 12:18:59 +03:00
2020-08-11 12:55:29 +03:00
if (content.indexOf('data:image') == 0) {
// Display Image
2012-04-29 22:10:04 +04:00
2020-08-12 15:02:13 +03:00
app.currentPaste.type = "image";
2020-08-14 19:18:17 +03:00
var pasteContent = document.querySelector('#paste-content');
2020-08-11 12:55:29 +03:00
pasteContent.style.display = "none";
2012-04-28 21:55:00 +04:00
2020-08-13 16:25:19 +03:00
var imgWrapper = document.createElement('div');
imgWrapper.classList.add('paste-wrapper');
var img = document.createElement('img');
2020-08-11 12:55:29 +03:00
img.src = content;
2020-08-13 16:25:19 +03:00
pasteContent.after(imgWrapper);
imgWrapper.appendChild(img);
2020-08-14 19:18:17 +03:00
document.querySelectorAll('.btn-clone').forEach(function (node) {
node.style.display = "none";
});
2020-08-14 19:18:17 +03:00
var extension = /data:image\/([^;]+);base64/.exec(content)[1];
2020-08-13 20:04:57 +03:00
app.currentPaste.downloadLink = {
2020-08-13 20:04:57 +03:00
name: '0bin_' + document.location.pathname.split('/').pop() + '.' + extension,
2020-08-11 12:55:29 +03:00
url: content
}
2020-08-12 15:02:13 +03:00
} else {
2020-08-14 19:18:17 +03:00
app.currentPaste.type = "text";
2020-08-13 20:04:57 +03:00
/* Decrypted content goes back to initial container*/
document.querySelector('#paste-content').innerText = content;
2020-08-14 19:18:17 +03:00
app.currentPaste.content = content;
2020-08-13 20:04:57 +03:00
app.currentPaste.downloadLink = {
2020-08-13 20:04:57 +03:00
name: '0bin_' + document.location.pathname.split('/').pop() + ".txt",
url: "data:text/html;charset=UTF-8," + content
}
2020-08-14 12:18:59 +03:00
if (app.support.URLSearchParams) {
readerMode = (new URLSearchParams(window.location.search)).get('readerMode');
}
2020-08-11 12:55:29 +03:00
}
bar.set('Code coloration...', '95%');
2020-08-14 19:18:17 +03:00
/* Add a continuation to var the UI redraw */
2020-08-11 12:55:29 +03:00
setTimeout(function () {
/** Syntaxic coloration */
2020-08-14 12:18:59 +03:00
if (zerobin.isCode(content) > 100 && !readerMode) {
2020-08-11 12:55:29 +03:00
document.getElementById('paste-content').classList.add('linenums');
prettyPrint();
} else {
if (content.indexOf('data:image') != 0) {
zerobin.message('primary',
2020-08-11 12:55:29 +03:00
"The paste did not seem to be code, so it " +
"was not colorized. ",
'', false, undefined, {
2020-08-15 13:05:22 +03:00
message: "Click here to force coloration",
2020-08-11 12:55:29 +03:00
callback: app.handleForceColoration
});
}
}
2020-08-11 12:55:29 +03:00
/* Class to switch to paste content style with coloration done */
document.getElementById('paste-content').classList.add('done');
2020-08-11 12:55:29 +03:00
/* Display result */
bar.set('Done', '100%');
app.isLoading = false;
2020-08-14 19:18:17 +03:00
form.forEach(function (node) {
node.disabled = false;
});
2020-08-11 12:55:29 +03:00
content = '';
2020-08-14 12:18:59 +03:00
if (readerMode) {
2020-08-14 19:18:17 +03:00
app.toggleReaderMode();
2020-08-14 12:18:59 +03:00
}
2012-05-23 18:20:46 +04:00
2020-08-11 12:55:29 +03:00
}, 100);
2020-08-11 12:55:29 +03:00
});
2020-08-11 12:55:29 +03:00
} /* End of "DECRYPTION" */
window.onload = function () {
2020-08-12 15:02:13 +03:00
/* Display bottom paste option buttons when needed */
2020-08-14 19:18:17 +03:00
["keyup", "change"].forEach(function (event) {
var content = document.getElementById("content");
content.addEventListener(event, function () {
var height = parseFloat(getComputedStyle(content, null).height.replace("px", ""))
2020-08-11 12:55:29 +03:00
app.displayBottomToolBar = height > 400;
})
})
/* Remove expired pasted from history **/
if (app.support.history && app.currentPaste.type === 'not_found') {
var paste_id = zerobin.getPasteId();
var keys = zerobin.getLocalStorageURLKeys();
2020-08-14 19:18:17 +03:00
keys.forEach(function (key, i) {
if (localStorage[key].indexOf(paste_id) !== -1) {
localStorage.removeItem(key);
return false;
}
})
}
2020-08-14 19:18:17 +03:00
var title = document.querySelector('h1');
2020-08-14 16:08:55 +03:00
if (title) {
app.currentPaste.title = title.innerText;
}
2020-08-15 11:02:57 +03:00
var btcTipAddress = document.querySelector('.btc-tip-address');
2020-08-14 17:41:45 +03:00
if (btcTipAddress) {
app.currentPaste.btcTipAddress = btcTipAddress.innerText;
}
2020-08-11 12:55:29 +03:00
}
/* Display previous pastes */
if (app.support.localStorage) {
app.previousPastes = zerobin.getPreviousPastes();
2020-08-11 17:37:03 +03:00
app.currentPaste.ownerKey = localStorage.getItem('zerobinV' + zerobin.version + "#" + zerobin.getPasteId(window.location) + "#owner_key");
2020-08-11 12:55:29 +03:00
}
/* Upload file using HTML5 File API */
if (app.support.fileUpload) {
// Implements drag & drop upload
2020-08-14 19:18:17 +03:00
var content = document.getElementById('content');
2020-08-11 12:55:29 +03:00
content.addEventListener('drop', zerobin.handleDrop);
2020-08-13 19:14:19 +03:00
content.addEventListener('paste', zerobin.handlePaste);
2020-08-11 12:55:29 +03:00
content.addEventListener('dragover', zerobin.handleDragOver);
content.addEventListener('dragleave', zerobin.handleDragLeave);
}
2020-08-12 15:14:13 +03:00
/* Autofit text area height */
2020-08-14 19:18:17 +03:00
var tx = document.getElementsByTagName('textarea');
for (var i = 0; i < tx.length; i++) {
2020-08-12 15:14:13 +03:00
tx[i].setAttribute('style', 'height:' + (tx[i].scrollHeight) + 'px;overflow-y:hidden;');
tx[i].addEventListener("input", OnInput, false);
}
function OnInput() {
this.style.height = 'auto';
this.style.height = (this.scrollHeight) + 'px';
}