html5sticky.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /*
  2. HTML5STICKY (http://github.com/sarfraznawaz2005/HTML5Sticky)
  3. ================================================================
  4. Author : Sarfraz Ahmed ([email protected])
  5. Twitter : @sarfraznawaz
  6. Blog : http://sarfraznawaz.wordpress.com/
  7. LICENSE : MIT
  8. ================================================================
  9. @updated zhaoxianlie
  10. */
  11. let stickywidth = 220; // width of sticky note (can't be less than 200)
  12. let stickyheight = 200; // height of sticky note (can't be less than 200)
  13. let max_notes = 10000; // maximum number of notes one can store
  14. let allowed_tags = '<br /><br><ol></ol><ul></ul><li></li><strong></strong><i></i>';
  15. let html5sticky = {};
  16. const STICKYNOTES_ALLKEYS = 'stickynotes|allkeys';
  17. const STICKYNOTES_FOLDERS = 'stickynotes|folders';
  18. const STICKYNOTES_SELECTED_FOLDER = 'stickynotes|selected|folder';
  19. // add a note
  20. html5sticky.addNote = function () {
  21. // count total present notes
  22. let tnotes = $('.note_common').length;
  23. if (tnotes === max_notes) {
  24. html5sticky.showMessage('#FFE16B', 'black', '当前便签笔记已经足够多了,不能再添加了!');
  25. return false;
  26. }
  27. // unique localstorage identifier for this sticky note
  28. let nindex = 'stickynote_' + (new Date * 1);
  29. let dated = getDateTime();
  30. let dateStr = new Date();
  31. // get random color
  32. let bgcolor = html5sticky.getColor();
  33. let stickynote = $('<div class="note_common ' + bgcolor + '" />').appendTo($('#main'));
  34. // add tape to stickynote
  35. html5sticky.addPin(stickynote);
  36. $(stickynote).append($('<h2>' + dated + '</h2>'));
  37. $(stickynote).append($('<p></p>'));
  38. // append identifier
  39. $(stickynote).append($('<span id="idf_' + nindex + '" />'));
  40. // set width and height of the sticky note
  41. $('.note_common').css({width: stickywidth + 'px', height: stickyheight + 'px'});
  42. $('.note_common p').css({height: (stickyheight - 60) + 'px', width: (stickywidth + 9) + 'px'});
  43. if (!$("#removenotes").is(':visible')) {
  44. $('#removenotes').slideDown('slow');
  45. }
  46. // scroll to newly added sticky note
  47. $('html, body').animate({
  48. scrollTop: $(stickynote).offset().top
  49. });
  50. // 先存key,再存数据
  51. let allKeys = (localStorage.getItem(STICKYNOTES_ALLKEYS) || '').split(',');
  52. allKeys.push(nindex + '|text');
  53. allKeys.push(nindex + '|bgcolor');
  54. allKeys.push(nindex + '|dated');
  55. allKeys.push(nindex + '|folderid');
  56. localStorage.setItem(STICKYNOTES_ALLKEYS, allKeys.join(','));
  57. // 存数据
  58. localStorage.setItem(nindex, nindex);
  59. localStorage.setItem(nindex + '|text', $(stickynote).find('h2').text() + '|' + $(stickynote).find('p').text());
  60. localStorage.setItem(nindex + '|bgcolor', bgcolor);
  61. localStorage.setItem(nindex + '|dated', dated + '|' + getISODateTime(dateStr));
  62. let folder = html5sticky.getCurrentFolder();
  63. localStorage.setItem(nindex + '|folderid', folder[1]);
  64. html5sticky.enlargeNote(stickynote);
  65. };
  66. // save note
  67. html5sticky.saveNote = function (el) {
  68. let identifier = html5sticky.getIdentifier($(el));
  69. let htext = html5sticky.stripTags($(el).closest('.bignote').find('.hedit')[0].value, allowed_tags);
  70. let ptext = html5sticky.stripTags($(el).closest('.bignote').find('.pedit')[0].value, allowed_tags);
  71. ptext = ptext.replace(/\r?\n/g, '<br />');
  72. localStorage.setItem(identifier + '|text', htext + '|' + ptext);
  73. $('[id^=idf_' + identifier + ']').closest('.note_common').find('h2').text(htext);
  74. $('[id^=idf_' + identifier + ']').closest('.note_common').find('p').html(ptext);
  75. html5sticky.showMessage('#9BED87', 'black', '笔记保存成功!');
  76. };
  77. // get note identifier
  78. html5sticky.getIdentifier = function (el) {
  79. let identifier = $(el).closest('.bignote').find('[id^=idf_]').attr('id');
  80. if (typeof identifier == 'undefined' || identifier == null) {
  81. identifier = $(el).closest('.note_common').find('[id^=idf_]').attr('id');
  82. }
  83. if (typeof identifier != 'undefined') {
  84. identifier = identifier.replace('idf_', '');
  85. return identifier;
  86. }
  87. else {
  88. return false;
  89. }
  90. };
  91. // delete note
  92. html5sticky.deleteNote = function (el) {
  93. if (confirm('确定要删除这个便签笔记吗,一旦删除则不可恢复,请三思?')) {
  94. let identifier = html5sticky.getIdentifier($(el));
  95. localStorage.removeItem(identifier);
  96. localStorage.removeItem(identifier + '|text');
  97. localStorage.removeItem(identifier + '|bgcolor');
  98. localStorage.removeItem(identifier + '|dated');
  99. localStorage.removeItem(identifier + '|folderid');
  100. let allKeys = (localStorage.getItem(STICKYNOTES_ALLKEYS) || '').split(',');
  101. ['text', 'bgcolor', 'dated', 'folderid'].forEach(function (item) {
  102. let id = identifier + '|' + item;
  103. allKeys.indexOf(id) > -1 && allKeys.splice(allKeys.indexOf(id), 1);
  104. });
  105. localStorage.setItem(STICKYNOTES_ALLKEYS, allKeys.join(','));
  106. $(el).closest('.note_common').fadeOut('slow', function () {
  107. $(el).closest('.note_common').remove();
  108. if (!$(".note_common").length > 0) {
  109. $('#removenotes').slideUp('slow');
  110. }
  111. });
  112. }
  113. };
  114. // delete all notes
  115. html5sticky.deleteAllNotes = function () {
  116. if (confirm('确定要删除所有笔记吗,一旦删除则不可恢复,请三思?')) {
  117. $('.note_common').fadeOut('slow', function () {
  118. $('.note_common').remove();
  119. let allKeys = (localStorage.getItem(STICKYNOTES_ALLKEYS) || '').split(',');
  120. allKeys.forEach(function (key) {
  121. localStorage.removeItem(key);
  122. });
  123. localStorage.removeItem(STICKYNOTES_ALLKEYS);
  124. });
  125. }
  126. };
  127. // close big note
  128. html5sticky.closeNote = function (el) {
  129. $(el).closest('.bignote')[html5sticky.getAnimation(true)]('slow', function () {
  130. $('#overlay').remove();
  131. });
  132. };
  133. // edit note
  134. html5sticky.editNote = function ($clone, el) {
  135. let ptext = $clone.find('p').html();
  136. ptext = ptext.replace(/(<br \/>|<br>)/g, '\n');
  137. $clone.find('p').replaceWith('<textarea class="pedit" placeholder="在这里添加笔记" />');
  138. $clone.find('.pedit')
  139. .val(ptext)
  140. .css({
  141. 'marginTop': '5px',
  142. 'resize': 'none',
  143. 'outline': 'none'
  144. })
  145. .addClass('inset')
  146. .width('568px')
  147. .height('280px');
  148. // make content editable
  149. let htext = $clone.find('h2').text();
  150. $clone.find('h2').replaceWith('<input type="text" class="hedit" />');
  151. $('.hedit').addClass('inset').val(html5sticky.stripTags(htext, allowed_tags)).width(250);
  152. // put in Close button
  153. $('<a href="#" class="close_stickynote"><img src="./img/delete.png" alt="" title="关闭笔记"></a>')
  154. .css({
  155. position: 'absolute',
  156. top: 7,
  157. right: 5
  158. })
  159. .appendTo($clone);
  160. // put in Save button
  161. $('<a href="#" class="save_stickynote"><img src="./img/save.png" alt="" title="保存笔记"></a>')
  162. .css({
  163. position: 'absolute',
  164. top: 5,
  165. right: 50
  166. })
  167. .appendTo($clone);
  168. };
  169. // get all notes
  170. html5sticky.getNotes = function (folderId) {
  171. let mainEl = $('#main').html('');
  172. let allKeys = (localStorage.getItem(STICKYNOTES_ALLKEYS) || '').split(',');
  173. allKeys.forEach(key => {
  174. if (!/\|text/.test(key)) {
  175. return false;
  176. }
  177. let id = key.replace('|text', '');
  178. let stickynote, bgcolor, htext, ptext, temp_array, folderid;
  179. // 按照folder id寻找对应目录下的便签
  180. folderid = localStorage.getItem(id + '|folderid') || '0';
  181. if (folderId !== folderid) {
  182. return false;
  183. }
  184. // get color and rotation level
  185. bgcolor = localStorage.getItem(id + '|bgcolor');
  186. // get text info
  187. temp_array = localStorage.getItem(id + '|text').split('|');
  188. htext = temp_array[0];
  189. ptext = temp_array[1];
  190. stickynote = $('<div class="note_common ' + bgcolor + '" />').appendTo(mainEl);
  191. html5sticky.addPin(stickynote);
  192. $(stickynote).append($('<h2></h2>'));
  193. $(stickynote).append($('<p></p>'));
  194. // append identifier
  195. $(stickynote).append($('<span id="idf_' + id + '" />'));
  196. $(stickynote).find('h2').text(html5sticky.stripTags(htext, allowed_tags));
  197. $(stickynote).find('p').html(html5sticky.stripTags(ptext, allowed_tags));
  198. // set width and height of the sticky note
  199. $('.note_common').css({width: stickywidth + 'px', height: stickyheight + 'px'});
  200. $('.note_common p').css({height: (stickyheight - 60) + 'px', width: (stickywidth - 24) + 'px'});
  201. });
  202. };
  203. // collapse notes
  204. html5sticky.collapse = function () {
  205. let height = parseInt($('.note_common:first').find('h2').height() || 0, 10) + 'px';
  206. $('.note_common').animate({height: height}, function () {
  207. $('.note_common').find('p').hide();
  208. });
  209. };
  210. // expand notes
  211. html5sticky.expand = function () {
  212. $('.note_common').animate({height: stickyheight}, function () {
  213. $('.note_common').find('p').fadeIn('slow');
  214. });
  215. };
  216. // share note
  217. html5sticky.showMessage = function (bgcolor, color, msg) {
  218. if (!$('#smsg').is(':visible')) {
  219. $('html, body').animate({
  220. scrollTop: 0
  221. }, 500, function () {
  222. if (!$('#smsg').length) {
  223. $('<div id="smsg">' + msg + '</div>').appendTo($('body')).css({
  224. position: 'absolute',
  225. top: 0,
  226. left: 0,
  227. right: 0,
  228. height: '40px',
  229. lineHeight: '40px',
  230. background: bgcolor,
  231. color: color,
  232. zIndex: 1000,
  233. fontWeight: 'bold',
  234. textAlign: 'center',
  235. opacity: 0.9,
  236. margin: 'auto',
  237. display: 'none'
  238. }).slideDown('show');
  239. setTimeout(function () {
  240. $('#smsg').animate({'width': 'hide'}, function () {
  241. $('#smsg').remove();
  242. });
  243. }, 2000);
  244. }
  245. });
  246. }
  247. };
  248. // get random color
  249. html5sticky.getColor = function () {
  250. let text = "";
  251. let possible = "0123456789";
  252. text += possible.charAt(Math.floor(Math.random() * possible.length));
  253. return 'stickynote' + text;
  254. };
  255. // get random animation string
  256. html5sticky.getAnimation = function (hideAnimation) {
  257. let words = [];
  258. if (typeof hideAnimation !== 'undefined') {
  259. words[1] = "hide";
  260. words[2] = "fadeOut";
  261. words[3] = "slideUp";
  262. }
  263. else {
  264. words[1] = "show";
  265. words[2] = "fadeIn";
  266. words[3] = "slideDown";
  267. }
  268. // Generate a random number between 1 and 3
  269. let rnd = Math.ceil(Math.random() * 3);
  270. return words[rnd];
  271. };
  272. // add pin to note
  273. html5sticky.addPin = function (el) {
  274. let close = $('<div class="btn-close"><a href="#" class="delete_stickynote"><img src="./img/delete.png" width="24" alt="" title="删除笔记"></a></div>');
  275. let tag = $('<div align="center"><img src="./img/pin.png" alt="" title="关闭"></div>');
  276. $(close).css({
  277. position: 'absolute',
  278. top: -15,
  279. right: -15
  280. }).hide().prependTo($(el));
  281. $(tag).css({
  282. position: 'absolute',
  283. zIndex: 99,
  284. top: -15,
  285. left: parseInt(stickywidth / 2, 10) - 10
  286. }).prependTo($(el));
  287. };
  288. // enlarge note for editing
  289. html5sticky.enlargeNote = function (el) {
  290. $this = $(el);
  291. // create overlay
  292. $('<div id="overlay" />').css({
  293. position: 'fixed',
  294. background: 'rgba(0,0,0,0.5)',
  295. top: '0',
  296. left: '0',
  297. width: '100%',
  298. height: '100%',
  299. zIndex: '100'
  300. }).appendTo($('body'));
  301. $clone = $(el).clone().removeClass('note_common').addClass('bignote').appendTo($('#overlay'));
  302. // remove the pin
  303. $clone.find($('img[src*="pin.png"]').closest('div')).hide();
  304. // change delete button title
  305. $clone.find($('img[src*="delete.png"]').closest('div')).hide();
  306. $($clone).css({
  307. position: 'absolute',
  308. zIndex: 500,
  309. cursor: 'default',
  310. paddingTop: '5px',
  311. width: '600px',
  312. height: '376px',
  313. top: '50%',
  314. left: '50%',
  315. display: 'none',
  316. marginLeft: '-300px',
  317. marginTop: '-200px'
  318. });
  319. $($clone)[html5sticky.getAnimation()](400);
  320. // add date and time info
  321. let dateStr = '', dateAgo = '';
  322. let identifier = html5sticky.getIdentifier($(el));
  323. let dateTime = localStorage.getItem(identifier + '|dated');
  324. let timeImg = '<img class="left" align="absmiddle" src="./img/time.png">';
  325. dateStr = dateTime.split('|')[0];
  326. dateAgo = prettyDate(dateTime.split('|')[1]);
  327. dateStr = (dateStr.length > 0) ? '创建于:' + dateStr : '';
  328. dateAgo = (dateAgo.length > 0) ? ' (' + dateAgo + ')' : '';
  329. timeImg = (dateStr.length > 0) ? timeImg : '';
  330. $('<div class="timeago left" />').prependTo($clone);
  331. $('.timeago').css({fontSize: '12px', fontFamily: 'tahoma'})
  332. .html(timeImg + '&nbsp;&nbsp;' + dateStr + dateAgo)
  333. .after('<div class="clear" />');
  334. // hide the utility buttons
  335. $($clone).find('.icons-footer').hide();
  336. // make content editable
  337. html5sticky.editNote($clone, el);
  338. };
  339. // http://phpjs.org/functions/strip_tags:535
  340. html5sticky.stripTags = function (input, allowed) {
  341. allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join('');
  342. let tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
  343. commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
  344. return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
  345. return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
  346. });
  347. };
  348. // 全部notes导出到本地
  349. html5sticky.export = function () {
  350. chrome.permissions.request({
  351. permissions: ['downloads']
  352. }, (granted) => {
  353. if (granted) {
  354. let allKeys = (localStorage.getItem(STICKYNOTES_ALLKEYS) || '').split(',');
  355. let zipper = null;
  356. if (allKeys.length) {
  357. zipper = new JSZip();
  358. }
  359. let zpFolder = {};
  360. allKeys.forEach(key => {
  361. if (!/\|text/.test(key)) {
  362. return false;
  363. }
  364. let id = key.replace('|text', '');
  365. let dated, htext, ptext, temp_array, folderid;
  366. dated = localStorage.getItem(id + '|dated');
  367. folderid = localStorage.getItem(id + '|folderid') || '0';
  368. if (!zpFolder[folderid]) {
  369. let forderName = html5sticky.findFolderNameById(folderid);
  370. zpFolder[folderid] = zipper.folder(forderName);
  371. }
  372. // get text info
  373. temp_array = localStorage.getItem(id + '|text').split('|');
  374. htext = temp_array[0];
  375. ptext = temp_array[1];
  376. zpFolder[folderid].file(htext + '.txt', [
  377. '# title:' + htext,
  378. '# date:' + dated,
  379. '# content:\n' + ptext
  380. ].join('\n\n'));
  381. });
  382. if (zipper) {
  383. zipper.generateAsync({type: "blob"})
  384. .then(function (content) {
  385. chrome.downloads.download({
  386. url: URL.createObjectURL(new Blob([content], {type: 'application/octet-stream'})),
  387. saveAs: true,
  388. conflictAction: 'overwrite',
  389. filename: '我的便签笔记-' + (new Date * 1) + '.zip'
  390. });
  391. });
  392. }
  393. } else {
  394. alert('必须接受授权,才能正常下载!');
  395. }
  396. });
  397. };
  398. html5sticky.buildFoldersAndInitNotes = function () {
  399. let folders = html5sticky.loadFolders();
  400. Object.keys(folders).forEach((f, idx) => {
  401. html5sticky.createFolder(f, folders[f]);
  402. });
  403. let current = html5sticky.getCurrentFolder();
  404. $('li#f_' + current[1]).addClass('x-selected');
  405. html5sticky.getNotes(current[1]);
  406. };
  407. html5sticky.loadFolders = function () {
  408. let folders = JSON.parse(localStorage.getItem(STICKYNOTES_FOLDERS) || '{}') || {};
  409. if (!folders['默认文件夹']) {
  410. folders['默认文件夹'] = '0';
  411. }
  412. return folders;
  413. };
  414. html5sticky.saveFolder = function (folder, time) {
  415. let folders = html5sticky.loadFolders();
  416. folders[folder] = time;
  417. localStorage.setItem(STICKYNOTES_FOLDERS, JSON.stringify(folders));
  418. };
  419. html5sticky.createFolder = function (folder, time) {
  420. folder = folder || window.prompt('新建文件夹');
  421. if (folder) {
  422. if (!time) {
  423. let folders = html5sticky.loadFolders();
  424. if (folders[folder]) {
  425. return alert('你已经创建过这个文件夹!');
  426. }
  427. }
  428. time = time || new Date().getTime();
  429. html5sticky.saveFolder(folder, time);
  430. return $('<li/>').text(folder).attr('id', 'f_' + time).appendTo('#folders');
  431. } else {
  432. return alert('文件夹名不能为空!');
  433. }
  434. };
  435. html5sticky.getCurrentFolder = function () {
  436. let folder = JSON.parse(localStorage.getItem(STICKYNOTES_SELECTED_FOLDER) || '[]') || [];
  437. if (!folder.length) {
  438. folder = ['默认文件夹', '0'];
  439. }
  440. return folder;
  441. };
  442. html5sticky.setCurrentFolder = function (txt, id) {
  443. localStorage.setItem(STICKYNOTES_SELECTED_FOLDER, JSON.stringify([txt, id]));
  444. };
  445. html5sticky.findFolderNameById = function (folderId) {
  446. let folders = html5sticky.loadFolders();
  447. let arr = Object.keys(folders).filter(f => String(folders[f]) === String(folderId));
  448. return arr.length ? arr[0] : '默认文件夹';
  449. };