app.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. (function(global, noGlobal) {
  2. class StickyNote {
  3. constructor(options) {
  4. this.init(options);
  5. }
  6. init(options) {
  7. Object.assign(this, config, options);
  8. this.id = this.id ? this.id : new Date().getTime();
  9. StickyNote.top = Math.max(StickyNote.top, this.layer);
  10. if(!this.root) {
  11. this.root = document.body;
  12. }
  13. this.container = document.createElement('div');
  14. this.container.classList.add(this.className || 'note-container');
  15. this.root.appendChild(this.container);
  16. this.render();
  17. this.bindEvent();
  18. }
  19. save() {
  20. this.content = this.noteContent.innerHTML;
  21. store.set(this.id, {
  22. content: this.content || '',
  23. postTime: new Date().getTime(),
  24. x: this.x,
  25. y: this.y,
  26. layer: this.layer
  27. });
  28. }
  29. close() {
  30. if (this.root) {
  31. this.root.removeChild(this.container);
  32. }
  33. }
  34. bindEvent() {
  35. var pos = {}, self = this, canMove = false;
  36. addEvent(this.titleBar, 'mousedown', function(e) {
  37. pos.x = e.clientX - self.container.offsetLeft;
  38. pos.y = e.clientY - self.container.offsetTop;
  39. if (e.button == 0) {
  40. canMove = true;
  41. }
  42. });
  43. addEvent(document, 'mousemove', function(e) {
  44. if (!canMove) return;
  45. var
  46. x = Math.min( document.documentElement.clientWidth - self.width, Math.max(e.clientX - pos.x, 0)),
  47. y = Math.min( document.documentElement.clientHeight - self.height, Math.max(e.clientY - pos.y, 0));
  48. self.container.style.left = x + 'px';
  49. self.container.style.top = y + 'px';
  50. });
  51. addEvent(document, 'mouseup', function(e) {
  52. canMove = false;
  53. });
  54. addEvent(self.noteContent, 'keyup', function(e) {
  55. self.save();
  56. });
  57. addEvent(self.btnClose, 'click', function(e) {
  58. self.close();
  59. self.save();
  60. })
  61. addEvent(self.btnNew, 'click', function(e) {
  62. var x = self.x,
  63. y = self.y,
  64. maxWidth = document.documentElement.clientWidth - self.width,
  65. maxHeight = document.documentElement.clientHeight - self.height;
  66. if ( x >= maxWidth || x < 0 ) {
  67. vx *= -1;
  68. }
  69. if ( y >= maxHeight || y < 0 ) {
  70. vy *= -1;
  71. }
  72. x = x + 20 * vx;
  73. y = y + 20 * vy;
  74. new StickyNote({
  75. root: self.root,
  76. x: x,
  77. y: y,
  78. layer: StickyNote.top++
  79. });
  80. });
  81. addEvent(self.btnRemove, 'click', function(e) {
  82. store.remove(self.id);
  83. self.close();
  84. })
  85. addEvent(self.container, 'mousedown', function(e) {
  86. if (e.button != 0) return;
  87. self.layer = StickyNote.top++;
  88. self.container.style.zIndex = self.layer;
  89. });
  90. addEvent(self.container, 'mouseup', function(e) {
  91. self.x = self.container.offsetLeft || 0;
  92. self.y = self.container.offsetTop || 0;
  93. self.save();
  94. });
  95. }
  96. render() {
  97. var self = this;
  98. self.container.innerHTML = template.replace(/\{\{([^\}]+)\}\}/g, ($0, $1) => self[$1]);
  99. self.titleBar = self.container.querySelector('.note-title');
  100. self.noteContent = self.container.querySelector('.note-content');
  101. self.btnClose = self.container.querySelector('.btn-close');
  102. self.btnNew = self.container.querySelector('.btn-new');
  103. self.btnRemove = self.container.querySelector('.btn-remove');
  104. self.container.style.position = 'absolute';
  105. self.container.style.left = self.x + 'px';
  106. self.container.style.top = self.y + 'px';
  107. self.noteContent.innerHTML = self.content;
  108. self.container.data = self;
  109. self.container.style.zIndex = self.layer;
  110. self.save();
  111. }
  112. }
  113. StickyNote.top = 0;
  114. var vx = 1, vy = 1;
  115. const config = {
  116. id: null,
  117. root: null,
  118. title: '便笺',
  119. btnCloseTip: '关闭',
  120. textBtnNew: '新建笔记',
  121. textBtnRemove: '删除笔记',
  122. container: null,
  123. titleBar: null,
  124. width: 300,
  125. height: 400,
  126. x: 0,
  127. y: 0,
  128. layer: 0,
  129. content: '',
  130. };
  131. const template = [
  132. '<div class="note-title">',
  133. ' <h6>{{title}}</h6>',
  134. ' <a href="javascript:;" title="{{btnCloseTip}}" class="btn-close">&times;</a>',
  135. '</div>',
  136. '<div class="note-content" contenteditable="true"></div>',
  137. '<div class="note-footer">',
  138. ' <button class="btn-new">{{textBtnNew}}</button>',
  139. ' <button class="btn-remove">{{textBtnRemove}}</button>',
  140. '</div>'
  141. ].join('\n');
  142. function addEvent(el, type, fn) {
  143. var ieType = 'on' + type;
  144. if ('addEventListener' in window) {
  145. addEventListener.call(el, type, fn, false);
  146. } else if ('attachEvent' in el) {
  147. attachEvent.call(el, ieType, fn, false);
  148. } else {
  149. el[ieType] = fn;
  150. }
  151. }
  152. function removeEvent(el, type, fn) {
  153. var ieType = 'on' + type;
  154. if ('removeEventListener' in window) {
  155. removeEventListener.call(el, type, fn, false);
  156. } else if ('dispatchEvent' in el) {
  157. el.dispatch(ieType, fn);
  158. } else {
  159. el[ieType] = null;
  160. }
  161. }
  162. const store = {
  163. appId: 'stickyNote',
  164. data: {},
  165. get(id) {
  166. return store.data ? store.data[id] : {};
  167. },
  168. set(id, value) {
  169. store.data[id] = value;
  170. },
  171. remove(id) {
  172. delete store.data[id];
  173. },
  174. setup() {
  175. try {
  176. store.data = JSON.parse(localStorage[store.appId]) || {};
  177. } catch(e) {
  178. store.data = {};
  179. }
  180. var data = store.data;
  181. if ( !isEmpty(data) ) {
  182. for(var k in data) {
  183. new StickyNote({
  184. root: document.body,
  185. id: k,
  186. x: data[k].x,
  187. y: data[k].y,
  188. layer: data[k].layer,
  189. content: data[k].content
  190. });
  191. }
  192. } else {
  193. new StickyNote({
  194. root:document.body,
  195. x: (document.documentElement.clientWidth - config.width) / 2,
  196. y: (document.documentElement.clientHeight - config.height) / 2,
  197. });
  198. }
  199. window.onunload = function() {
  200. localStorage.setItem(store.appId, JSON.stringify(data));
  201. }
  202. },
  203. unsetup() {
  204. store.data = {};
  205. localStorage.removeItem(store.appId);
  206. window.onunload = null;
  207. }
  208. };
  209. function isEmpty(o) {
  210. if (typeof o === 'string' || Array.isArray(o) ) {
  211. return o.length === 0;
  212. } else if (typeof o === 'object') {
  213. for(let k in o) {
  214. if (!o.hasOwnProperty(k)) continue;
  215. return false;
  216. }
  217. return true;
  218. } else {
  219. return o == null;
  220. }
  221. }
  222. var domReady = {
  223. tasks: [],
  224. isReady: false,
  225. ready: function(fn) {
  226. domReady.tasks.push(fn);
  227. if (domReady.isReady) {
  228. return domReady.completed();
  229. } else {
  230. addEvent(document, 'DOMContentLoaded', domReady.completed);
  231. addEvent(document, 'readystatechange', function() {
  232. if ( /^(?:interactive|complete)$/.test(document.readyState)) {
  233. domReady.completed();
  234. removeEvent(document, 'readystatechange', arguments.callee);
  235. }
  236. });
  237. }
  238. },
  239. completed: function() {
  240. removeEvent(document, 'DOMContentLoaded', domReady.completed);
  241. domReady.isReady = true;
  242. domReady.execTasks();
  243. },
  244. execTasks: function() {
  245. while( domReady.tasks.length ) {
  246. domReady.tasks.shift()();
  247. };
  248. }
  249. }
  250. domReady.ready(store.setup);
  251. window.store = store;
  252. })();