A Chrome extension for Write.as
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

316 line
9.4 KiB

  1. var $content;
  2. var $publish;
  3. var $url;
  4. function publish(content, font) {
  5. if (content.trim() == "") {
  6. return;
  7. }
  8. $publish.classList.add('disabled');
  9. setPublishText(font, true);
  10. $publish.disabled = true;
  11. var post = H.getTitleStrict(content);
  12. var http = new XMLHttpRequest();
  13. var url = "https://write.as/api/posts";
  14. var lang = navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage);
  15. lang = lang.substring(0, 2);
  16. var params = "body=" + encodeURIComponent(post.content) + "&title=" + encodeURIComponent(post.title) + "&font=" + font + "&lang=" + lang + "&rtl=auto";
  17. http.open("POST", url, true);
  18. //Send the proper header information along with the request
  19. http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  20. http.onreadystatechange = function() {
  21. if (http.readyState == 4) {
  22. $publish.classList.remove('disabled');
  23. setPublishText(font, false);
  24. $publish.disabled = false;
  25. if (http.status == 201) {
  26. $publish.style.display = 'none';
  27. data = JSON.parse(http.responseText);
  28. // Pull out data parts
  29. id = data.data.id;
  30. if (font == 'code' || font === 'mono') {
  31. url = "https://paste.as/"+id;
  32. } else {
  33. url = "https://write.as/"+id;
  34. }
  35. editToken = data.data.token;
  36. document.getElementById("account-tools").style.display = 'none';
  37. document.getElementById("publish-holder").style.display = 'none';
  38. document.getElementById("result-holder").style.display = 'inline';
  39. $url = document.getElementById("url");
  40. $url.value = url;
  41. var $urlLink = document.getElementById("url-link");
  42. $urlLink.href = url;
  43. // Save the data if user wasn't logged in
  44. if (typeof data.data.owner === 'undefined' || data.data.owner == "") {
  45. posts = JSON.parse(H.get('posts', '[]'));
  46. posts.push(H.createPost(id, editToken, post.content));
  47. H.set('posts', JSON.stringify(posts));
  48. }
  49. } else {
  50. alert("Failed to post. Please try again.");
  51. }
  52. }
  53. }
  54. http.send(params);
  55. }
  56. function setPublishText(font, isPublishing) {
  57. if (font === 'code' || font === 'mono') {
  58. $publish.value = isPublishing ? 'Pasting...' : 'Paste';
  59. } else {
  60. $publish.value = isPublishing ? 'Publishing...' : 'Publish';
  61. }
  62. }
  63. document.addEventListener('DOMContentLoaded', function() {
  64. $content = document.getElementById("content");
  65. $publish = document.getElementById("publish");
  66. $url = document.getElementById("url");
  67. var $sync = document.getElementById('sync');
  68. var $modal = document.getElementById('modal');
  69. var fontRadios = document.postForm.font;
  70. var isPopout = window.location.search.substring(1) == "popout";
  71. if (isPopout) {
  72. chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  73. $content.value = request.msg;
  74. });
  75. }
  76. chrome.tabs.executeScript({
  77. code: "window.getSelection().toString();"
  78. }, function(selection) {
  79. if (typeof selection !== 'undefined') {
  80. $content.value = selection[0];
  81. }
  82. // load previous draft
  83. if ($content.value == "") {
  84. H.load($content, 'ext-draft');
  85. }
  86. });
  87. // focus on the paste field
  88. $content.focus();
  89. if (isPopout) {
  90. document.body.className = 'popout';
  91. } else {
  92. document.getElementById('popout').addEventListener('click', function(e) {
  93. e.preventDefault();
  94. chrome.windows.create({
  95. url: "popup.html?popout",
  96. width: 640,
  97. height: 400,
  98. focused: true,
  99. type: "popup"
  100. }, function(window) {
  101. chrome.runtime.sendMessage({msg: $content.value});
  102. });
  103. });
  104. document.querySelector('#modal .secondary').addEventListener('click', function(e) {
  105. e.preventDefault();
  106. $modal.style.display = 'none';
  107. });
  108. $sync.addEventListener('click', function(e) {
  109. e.preventDefault();
  110. var posts = JSON.parse(H.get('posts', '[]'));
  111. if (posts.length == 0) {
  112. return;
  113. }
  114. if ($modal.style.display == 'block') {
  115. $modal.style.display = 'none';
  116. return;
  117. }
  118. var p = "<p>There ";
  119. p += ((posts.length==1?'is':'are') + ' <strong>' + posts.length + " post" + (posts.length==1?'':'s'));
  120. var thePosts = posts.length == 1 ? 'it' : 'them';
  121. p += "</strong> saved on this computer.</p><p>Syncing "+thePosts+" to your account will give you access to "+thePosts+" from anywhere. Sync now?</p>";
  122. $modal.style.display = 'block';
  123. document.getElementById('modal-body').innerHTML = p;
  124. });
  125. document.querySelector('#modal .primary').addEventListener('click', function(e) {
  126. e.preventDefault();
  127. $modal.style.display = 'none';
  128. var posts = JSON.parse(H.get('posts', '[]'));
  129. $sync.innerText = "Syncing now...";
  130. $sync.className = 'disabled';
  131. var http = new XMLHttpRequest();
  132. var params = [];
  133. for (var i=0; i<posts.length; i++) {
  134. params.push({id: posts[i].id, token: posts[i].token});
  135. }
  136. http.open("POST", "https://write.as/api/posts/claim", true);
  137. http.setRequestHeader("Content-type", "application/json");
  138. http.onreadystatechange = function() {
  139. if (http.readyState == 4) {
  140. $sync.innerText = 'Importing now...';
  141. if (http.status == 200) {
  142. var res = JSON.parse(http.responseText);
  143. if (res.data.length > 0) {
  144. if (res.data.length != posts.length) {
  145. // TODO: handle this serious situation
  146. console.error("Request and result array length didn't match!");
  147. return;
  148. }
  149. for (var i=0; i<res.data.length; i++) {
  150. if (res.data[i].code == 200 || res.data[i].code == 404) {
  151. // Post successfully claimed.
  152. for (var j=0; j<posts.length; j++) {
  153. // Find post in local store
  154. var id = res.data[i].id;
  155. if (typeof res.data[i].post !== 'undefined') {
  156. id = res.data[i].post.id;
  157. }
  158. if (posts[j].id == id) {
  159. // Remove this post
  160. posts.splice(j, 1);
  161. break;
  162. }
  163. }
  164. } else {
  165. for (var j=0; j<posts.length; j++) {
  166. // Find post in local store
  167. if (posts[j].id == res.data[i].id) {
  168. // Note the error in the local post
  169. posts[j].error = res.data[i].error_msg;
  170. break;
  171. }
  172. }
  173. }
  174. }
  175. H.set('posts', JSON.stringify(posts));
  176. $sync.innerText = 'Synced.';
  177. }
  178. } else {
  179. // TODO: show error visually (option to retry)
  180. console.error("Well that didn't work at all!");
  181. $sync.className = '';
  182. $sync.innerText = 'Sync...';
  183. }
  184. }
  185. };
  186. http.send(JSON.stringify(params));
  187. });
  188. }
  189. // bind publish action
  190. $publish.addEventListener('click', function(e) {
  191. e.preventDefault();
  192. publish($content.value, fontRadios.value);
  193. });
  194. $content.addEventListener('keydown', function(e){
  195. if (e.ctrlKey && e.keyCode == 13) {
  196. e.preventDefault();
  197. publish($content.value, fontRadios.value);
  198. }
  199. });
  200. // bind URL select-all action
  201. $url.addEventListener('focus', function(e) {
  202. e.preventDefault();
  203. this.select();
  204. });
  205. // load font setting
  206. H.load(fontRadios, 'font');
  207. $content.className = fontRadios.value;
  208. setPublishText(fontRadios.value, false);
  209. // bind font changing action
  210. for(var i = 0; i < fontRadios.length; i++) {
  211. fontRadios[i].onclick = function() {
  212. $content.className = this.value;
  213. setPublishText(this.value, false);
  214. H.save(fontRadios, 'font');
  215. };
  216. }
  217. var handleRegUser = function() {
  218. var http = new XMLHttpRequest();
  219. http.open("GET", "https://write.as/api/me/", true);
  220. http.onreadystatechange = function() {
  221. if (http.readyState == 4) {
  222. data = JSON.parse(http.responseText);
  223. data = data.data;
  224. if (typeof data.username !== 'undefined' && data.username != "") {
  225. var $accTools = document.getElementById("account-tools")
  226. $accTools.style.display = 'block';
  227. var posts = JSON.parse(H.get('posts', '[]'));
  228. if (posts.length > 0) {
  229. $sync.style.display = 'inline';
  230. } else {
  231. $sync.style.display = 'none';
  232. }
  233. //document.getElementById("sync-count").innerText = posts.length + " post" + (posts.length==1?'':'s');
  234. document.getElementById("username").innerText = data.username;
  235. }
  236. }
  237. }
  238. http.send();
  239. }
  240. handleRegUser();
  241. if (H.get('updatedPostsMeta', '') == '') {
  242. // Add metadata used by Pad to all saved posts
  243. var addPostMetaData = function() {
  244. console.log('Adding post meta data...');
  245. var fetch = function(id, token, callback) {
  246. var http = new XMLHttpRequest();
  247. http.open("GET", "https://write.as/api/" + id + "?created=1&t=" + token, true);
  248. http.onreadystatechange = function() {
  249. if (http.readyState == 4) {
  250. callback(http.responseText, http.status);
  251. }
  252. }
  253. http.send();
  254. }
  255. var posts = JSON.parse(H.get('posts', '[]'));
  256. var migratedPosts = [];
  257. var failedPosts = [];
  258. if (posts.length > 0) {
  259. var i = 0;
  260. var updateMeta = function(content, status) {
  261. if (status == 200) {
  262. data = content.split("\n\n");
  263. created = data.splice(0, 1);
  264. migratedPosts.push(H.createPost(posts[i].id, posts[i].token, data.join("\n\n"), created));
  265. } else {
  266. posts[i].reason = status;
  267. failedPosts.push(posts[i]);
  268. }
  269. i++;
  270. if (i < posts.length) {
  271. fetch(posts[i].id, posts[i].token, updateMeta);
  272. } else {
  273. console.log('Finished! Success: ' + migratedPosts.length + '. Fail: ' + failedPosts.length);
  274. if (failedPosts.length > 0) {
  275. H.set('failedMigrationPosts', JSON.stringify(failedPosts));
  276. }
  277. H.set('posts', JSON.stringify(migratedPosts));
  278. H.set('updatedPostsMeta', 'yes');
  279. }
  280. };
  281. fetch(posts[i].id, posts[i].token, updateMeta);
  282. } else {
  283. H.set('updatedPostsMeta', 'yes');
  284. }
  285. };
  286. addPostMetaData();
  287. }
  288. });