@@ -78,4 +78,22 @@ var H = { | |||
return post; | |||
}, | |||
getTitleStrict: function(content) { | |||
var eol = content.indexOf("\n"); | |||
var title = ""; | |||
var newContent = content; | |||
if (content.indexOf("# ") === 0) { | |||
// Title is in the format: | |||
// # Some title | |||
if (eol !== -1) { | |||
// First line should start with # and end with \n | |||
newContent = content.substring(eol).leftTrim(); | |||
title = content.substring("# ".length, eol); | |||
} | |||
} | |||
return { | |||
title: title, | |||
content: newContent | |||
}; | |||
}, | |||
}; |
@@ -1,9 +1,9 @@ | |||
Paste Chrome extension | |||
====================== | |||
Write.as Chrome extension | |||
========================= | |||
Paste lets you instantly share text or code from your browser. | |||
Write.as for Chrome lets you instantly share text from your browser. | |||
![Selecting text in Paste](https://paste.as/images/pic01.jpg) | |||
![Selecting text in Write.as](https://paste.as/images/pic01.jpg) | |||
# License | |||
@@ -1,9 +1,14 @@ | |||
function publish(content, font) { | |||
if (content.trim() == "") { | |||
return; | |||
} | |||
var post = H.getTitleStrict(content); | |||
var http = new XMLHttpRequest(); | |||
var url = "https://write.as/api/"; | |||
var url = "https://write.as/api/posts"; | |||
var lang = navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage); | |||
lang = lang.substring(0, 2); | |||
var params = "w=" + encodeURIComponent(content) + "&font=" + font + "&lang=" + lang; | |||
var params = "body=" + encodeURIComponent(post.content) + "&title=" + encodeURIComponent(post.title) + "&font=" + font + "&lang=" + lang + "&rtl=auto"; | |||
http.open("POST", url, true); | |||
//Send the proper header information along with the request | |||
@@ -11,18 +16,24 @@ function publish(content, font) { | |||
http.onreadystatechange = function() { | |||
if (http.readyState == 4) { | |||
if (http.status == 200) { | |||
data = http.responseText.split("\n"); | |||
if (http.status == 201) { | |||
data = JSON.parse(http.responseText); | |||
// Pull out data parts | |||
url = data[0]; | |||
id = url.substr(url.lastIndexOf("/")+1); | |||
editToken = data[1]; | |||
// Save the data | |||
posts = JSON.parse(H.get('posts', '[]')); | |||
posts.push(H.createPost(id, editToken, content)); | |||
H.set('posts', JSON.stringify(posts)); | |||
id = data.data.id; | |||
if (font == 'code' || font === 'mono') { | |||
url = "https://paste.as/"+id; | |||
} else { | |||
url = "https://write.as/"+id; | |||
} | |||
editToken = data.data.token; | |||
// Save the data if user wasn't logged in | |||
if (typeof data.data.owner === 'undefined' || data.data.owner == "") { | |||
posts = JSON.parse(H.get('posts', '[]')); | |||
posts.push(H.createPost(id, editToken, post.content)); | |||
H.set('posts', JSON.stringify(posts)); | |||
} | |||
// Launch post | |||
chrome.tabs.create({ url: url }); | |||
} else { | |||
@@ -0,0 +1,18 @@ | |||
@font-face { | |||
font-family: 'Lora'; | |||
font-style: normal; | |||
font-weight: 400; | |||
src: local('Lora'), local('Lora-Regular'), url('fonts/lora.woff2') format('woff2'); | |||
} | |||
@font-face { | |||
font-family: 'Lora'; | |||
font-style: normal; | |||
font-weight: 700; | |||
src: local('Lora Bold'), local('Lora-Bold'), url('fonts/lora-700.woff2') format('woff2'); | |||
} | |||
@font-face { | |||
font-family: 'Open Sans'; | |||
font-style: normal; | |||
font-weight: 400; | |||
src: local('Open Sans'), local('OpenSans'), url('fonts/open-sans.woff2') format('woff2'); | |||
} |
@@ -0,0 +1,4 @@ | |||
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> | |||
<path d="M0 0h24v24H0z" fill="none"/> | |||
<path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/> | |||
</svg> |
@@ -1,9 +1,10 @@ | |||
{ | |||
"manifest_version": 2, | |||
"name": "Paste by Write.as", | |||
"description": "Effortlessly share text online.", | |||
"version": "1.3", | |||
"name": "Write.as for Chrome", | |||
"short_name": "Write.as", | |||
"description": "Publish a thought in seconds.", | |||
"version": "2.0", | |||
"icons": { | |||
"16": "icon16.png", | |||
@@ -28,8 +29,7 @@ | |||
"activeTab", | |||
"contextMenus", | |||
"webRequest", | |||
"*://*.write.as/", | |||
"https://fonts.googleapis.com/" | |||
"*://*.write.as/" | |||
], | |||
"externally_connectable": { | |||
"matches": ["*://*.write.as/*"] | |||
@@ -1,7 +1,7 @@ | |||
<!doctype html> | |||
<html> | |||
<head> | |||
<title>Paste by Write.as</title> | |||
<title>Write.as</title> | |||
<style> | |||
body, input[type=submit], label[for=norm], textarea.norm { | |||
font-family: Lora, serif; | |||
@@ -38,8 +38,15 @@ | |||
color: white; | |||
text-align: right; | |||
margin-left: 0.5em; | |||
width: 7em; | |||
text-align: center; | |||
transition: all .2s ease-out; | |||
border-radius: .25em; | |||
} | |||
input[type=submit].disabled { | |||
input[type=submit]:hover { | |||
background-color: #7d82c4; | |||
} | |||
input[type=submit].disabled, input[type=submit].disabled:hover { | |||
background: #ddd; | |||
color: #999; | |||
border-color: #eee; | |||
@@ -47,23 +54,38 @@ | |||
#publish-holder, #result-holder { | |||
text-align: right; | |||
} | |||
#result-holder { | |||
#result-holder, #account-tools { | |||
display: none; | |||
} | |||
#url { | |||
width: 18em; | |||
margin-right: 0.5em; | |||
} | |||
label[for=mono], label[for=code], textarea.mono, textarea.code { | |||
label[for=mono], label[for=wrap], label[for=code], textarea.mono, textarea.wrap, textarea.code { | |||
font-family: monospace, monospace; | |||
font-size: 1em; | |||
} | |||
textarea.mono, textarea.code { | |||
white-space: pre; | |||
} | |||
label, label[for=mono], label[for=wrap], label[for=code] { | |||
font-size: 0.86em; | |||
} | |||
body.popout #publish-holder, body.popout #result-holder { | |||
position: fixed; | |||
bottom: 1em; | |||
left: 1em; | |||
right: 1em; | |||
} | |||
#account-tools { | |||
margin-top: -0.5em; | |||
margin-bottom: 0.5em; | |||
font-size: 0.86em; | |||
} | |||
#account-tools a { | |||
line-height: 24px; | |||
margin-left: 0.5em; | |||
} | |||
body.popout textarea { | |||
position: fixed; | |||
top: 0; | |||
@@ -72,10 +94,29 @@ | |||
bottom: 4em; | |||
border: 0; | |||
border-bottom: 1px solid #dfdfdf; | |||
min-height: 0; | |||
} | |||
a#popout { | |||
padding: 0.5em; | |||
position: absolute; | |||
left: 0.75em; | |||
bottom: 0.75em; | |||
} | |||
a#popout img { | |||
vertical-align: middle; | |||
} | |||
body.popout a#popout { | |||
display: none; | |||
} | |||
#username { | |||
font-weight: bold; | |||
} | |||
#sync.disabled { | |||
display: inline; | |||
color: #999; | |||
font-style: italic; | |||
text-decoration: none; | |||
} | |||
</style> | |||
<script src="H.js"></script> | |||
@@ -83,23 +124,26 @@ | |||
</head> | |||
<body> | |||
<form name="postForm" method="post"> | |||
<textarea id="content" placeholder="Paste..."></textarea> | |||
<div id="account-tools"> | |||
Writing as <span id="username">write.as</span>. <a id="sync" href="#">Sync...</a> | |||
</div> | |||
<textarea id="content" placeholder="Write..."></textarea> | |||
<div id="result-holder"> | |||
<input id="url" type="url" readonly /> | |||
<a id="url-link" target="_blank">Open</a> | |||
</div> | |||
<div id="publish-holder"> | |||
<a href="#" id="popout">Pop out</a> | |||
<input type="radio" name="font" value="sans" id="sans" checked="checked" /><label for="sans"> Sans</label> | |||
<input type="radio" name="font" value="norm" id="norm" /><label for="norm"> Serif</label> | |||
<input type="radio" name="font" value="mono" id="mono" /><label for="mono"> Monospace</label> | |||
<input type="radio" name="font" value="wrap" id="wrap" /><label for="wrap"> Wrap</label> | |||
<input type="radio" name="font" value="code" id="code" /><label for="code"> Code</label> | |||
<input id="publish" type="submit" value="Publish" /> | |||
<a href="#" id="popout"><img src="img/ic_launch.svg" /></a> | |||
</div> | |||
</form> | |||
<link href='https://fonts.googleapis.com/css?family=Lora:400,700' rel='stylesheet' type='text/css'> | |||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'> | |||
<link href='fonts.css' rel='stylesheet' type='text/css'> | |||
</body> | |||
</html> | |||
@@ -8,14 +8,15 @@ function publish(content, font) { | |||
} | |||
$publish.classList.add('disabled'); | |||
$publish.value = "Publishing..."; | |||
setPublishText(font, true); | |||
$publish.disabled = true; | |||
var post = H.getTitleStrict(content); | |||
var http = new XMLHttpRequest(); | |||
var url = "https://write.as/api/"; | |||
var url = "https://write.as/api/posts"; | |||
var lang = navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage); | |||
lang = lang.substring(0, 2); | |||
var params = "w=" + encodeURIComponent(content) + "&font=" + font + "&lang=" + lang; | |||
var params = "body=" + encodeURIComponent(post.content) + "&title=" + encodeURIComponent(post.title) + "&font=" + font + "&lang=" + lang + "&rtl=auto"; | |||
http.open("POST", url, true); | |||
//Send the proper header information along with the request | |||
@@ -24,18 +25,23 @@ function publish(content, font) { | |||
http.onreadystatechange = function() { | |||
if (http.readyState == 4) { | |||
$publish.classList.remove('disabled'); | |||
$publish.value = "Publish"; | |||
setPublishText(font, false); | |||
$publish.disabled = false; | |||
if (http.status == 200) { | |||
if (http.status == 201) { | |||
$publish.style.display = 'none'; | |||
data = http.responseText.split("\n"); | |||
data = JSON.parse(http.responseText); | |||
// Pull out data parts | |||
url = data[0]; | |||
id = url.substr(url.lastIndexOf("/")+1); | |||
editToken = data[1]; | |||
id = data.data.id; | |||
if (font == 'code' || font === 'mono') { | |||
url = "https://paste.as/"+id; | |||
} else { | |||
url = "https://write.as/"+id; | |||
} | |||
editToken = data.data.token; | |||
document.getElementById("account-tools").style.display = 'none'; | |||
document.getElementById("publish-holder").style.display = 'none'; | |||
document.getElementById("result-holder").style.display = 'inline'; | |||
@@ -44,10 +50,12 @@ function publish(content, font) { | |||
var $urlLink = document.getElementById("url-link"); | |||
$urlLink.href = url; | |||
// Save the data | |||
posts = JSON.parse(H.get('posts', '[]')); | |||
posts.push(H.createPost(id, editToken, content)); | |||
H.set('posts', JSON.stringify(posts)); | |||
// Save the data if user wasn't logged in | |||
if (typeof data.data.owner === 'undefined' || data.data.owner == "") { | |||
posts = JSON.parse(H.get('posts', '[]')); | |||
posts.push(H.createPost(id, editToken, post.content)); | |||
H.set('posts', JSON.stringify(posts)); | |||
} | |||
} else { | |||
alert("Failed to post. Please try again."); | |||
} | |||
@@ -56,6 +64,14 @@ function publish(content, font) { | |||
http.send(params); | |||
} | |||
function setPublishText(font, isPublishing) { | |||
if (font === 'code' || font === 'mono') { | |||
$publish.value = isPublishing ? 'Pasting...' : 'Paste'; | |||
} else { | |||
$publish.value = isPublishing ? 'Publishing...' : 'Publish'; | |||
} | |||
} | |||
document.addEventListener('DOMContentLoaded', function() { | |||
$content = document.getElementById("content"); | |||
$publish = document.getElementById("publish"); | |||
@@ -99,6 +115,80 @@ document.addEventListener('DOMContentLoaded', function() { | |||
chrome.runtime.sendMessage({msg: $content.value}); | |||
}); | |||
}); | |||
document.getElementById('sync').addEventListener('click', function(e) { | |||
e.preventDefault(); | |||
var posts = JSON.parse(H.get('posts', '[]')); | |||
var p = "There "; | |||
p += ((posts.length==1?'is ':'are ') + posts.length + " post" + (posts.length==1?'':'s')); | |||
var thePosts = posts.length == 1 ? 'it' : 'them'; | |||
p += " saved on this computer.\n\nSyncing "+thePosts+" to your account gives you access to "+thePosts+" from anywhere. Sync now?"; | |||
if (!confirm(p)) { | |||
return; | |||
} | |||
var $sync = this; | |||
$sync.innerText = "Syncing now..."; | |||
$sync.className = 'disabled'; | |||
var http = new XMLHttpRequest(); | |||
var params = []; | |||
for (var i=0; i<posts.length; i++) { | |||
params.push({id: posts[i].id, token: posts[i].token}); | |||
} | |||
http.open("POST", "https://write.as/api/posts/claim", true); | |||
http.setRequestHeader("Content-type", "application/json"); | |||
http.onreadystatechange = function() { | |||
if (http.readyState == 4) { | |||
$sync.innerText = 'Importing now...'; | |||
if (http.status == 200) { | |||
var res = JSON.parse(http.responseText); | |||
if (res.data.length > 0) { | |||
if (res.data.length != posts.length) { | |||
// TODO: handle this serious situation | |||
console.error("Request and result array length didn't match!"); | |||
return; | |||
} | |||
for (var i=0; i<res.data.length; i++) { | |||
if (res.data[i].code == 200 || res.data[i].code == 404) { | |||
// Post successfully claimed. | |||
for (var j=0; j<posts.length; j++) { | |||
// Find post in local store | |||
var id = res.data[i].id; | |||
if (typeof res.data[i].post !== 'undefined') { | |||
id = res.data[i].post.id; | |||
} | |||
if (posts[j].id == id) { | |||
// Remove this post | |||
posts.splice(j, 1); | |||
break; | |||
} | |||
} | |||
} else { | |||
for (var j=0; j<posts.length; j++) { | |||
// Find post in local store | |||
if (posts[j].id == res.data[i].id) { | |||
// Note the error in the local post | |||
posts[j].error = res.data[i].error_msg; | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
H.set('posts', JSON.stringify(posts)); | |||
$sync.innerText = 'Synced.'; | |||
} | |||
} else { | |||
// TODO: show error visually (option to retry) | |||
console.error("Well that didn't work at all!"); | |||
$sync.className = ''; | |||
$sync.innerText = 'Sync...'; | |||
} | |||
} | |||
}; | |||
http.send(JSON.stringify(params)); | |||
}); | |||
} | |||
// bind publish action | |||
@@ -122,13 +212,40 @@ document.addEventListener('DOMContentLoaded', function() { | |||
// load font setting | |||
H.load(fontRadios, 'font'); | |||
$content.className = fontRadios.value; | |||
setPublishText(fontRadios.value, false); | |||
// bind font changing action | |||
for(var i = 0; i < fontRadios.length; i++) { | |||
fontRadios[i].onclick = function() { | |||
$content.className = this.value; | |||
setPublishText(this.value, false); | |||
H.save(fontRadios, 'font'); | |||
}; | |||
} | |||
var handleRegUser = function() { | |||
var http = new XMLHttpRequest(); | |||
http.open("GET", "https://write.as/api/me/", true); | |||
http.onreadystatechange = function() { | |||
if (http.readyState == 4) { | |||
data = JSON.parse(http.responseText); | |||
data = data.data; | |||
if (typeof data.username !== 'undefined' && data.username != "") { | |||
var $accTools = document.getElementById("account-tools") | |||
$accTools.style.display = 'block'; | |||
var posts = JSON.parse(H.get('posts', '[]')); | |||
if (posts.length > 0) { | |||
document.getElementById('sync').style.display = 'inline'; | |||
} else { | |||
document.getElementById('sync').style.display = 'none'; | |||
} | |||
//document.getElementById("sync-count").innerText = posts.length + " post" + (posts.length==1?'':'s'); | |||
document.getElementById("username").innerText = data.username; | |||
} | |||
} | |||
} | |||
http.send(); | |||
} | |||
handleRegUser(); | |||
if (H.get('updatedPostsMeta', '') == '') { | |||
// Add metadata used by Pad to all saved posts | |||