PageRenderTime 61ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/source/app/assets/js/models/sync.js

https://github.com/neekey/FreeNote
JavaScript | 323 lines | 198 code | 97 blank | 28 comment | 14 complexity | 7883095e4c7a6a1829054efe2d846d68 MD5 | raw file
  1. /**
  2. * sync table in client
  3. */
  4. (function( APP ){
  5. var MODS = APP.mods,
  6. MODELS = APP.models;
  7. var Mchange = Backbone.Model.extend({
  8. defaults: {
  9. type: null,
  10. date: null,
  11. id: null,
  12. _id: null,
  13. note: null
  14. },
  15. localStorage: new MODS.localStorageStore( 'changes' ),
  16. initialize: function(){
  17. this.bind( 'change', function(){
  18. this.save({}, {
  19. silent: true
  20. });
  21. }, this );
  22. },
  23. noteUpdate: function( m ){
  24. console.log( 'model change' );
  25. this.set({
  26. 'note': m.toJSON(),
  27. 'date': Date.now()
  28. });
  29. },
  30. noteDestroy: function( m ){
  31. this.set({
  32. 'note': m.toJSON(),
  33. 'date': Date.now(),
  34. 'type': 'del'
  35. });
  36. }
  37. }),
  38. CLchange = Backbone.Collection.extend({
  39. model: Mchange,
  40. localStorage: new MODS.localStorageStore( 'changes' ),
  41. initialize: function(){
  42. // 读取已经有的同步表信息
  43. this.fetch();
  44. },
  45. /**
  46. * 初始化fetch后执行
  47. * 寻找每一条变更对应的model,绑定事件
  48. * @param notes
  49. */
  50. bindModels: function( notes ){
  51. var that = this;
  52. this.forEach( function( m ){
  53. var model = notes.get( m.id );
  54. if( model ){
  55. model.bind( 'change', m.noteUpdate, m );
  56. model.bind( 'destroy', m.noteDestroy, m );
  57. }
  58. });
  59. },
  60. /**
  61. * 添加变更记录
  62. * @param m
  63. * @param type
  64. */
  65. addChange: function( m, type ){
  66. if( !m.get( 'syncMarked' ) && !this.get( m.id ) ){
  67. m.set({ 'syncMarked': true });
  68. var change = this.create({
  69. id: m.get( 'id' ),
  70. _id: m.get( '_id' ),
  71. type: type,
  72. date: Date.now(),
  73. note: m.toJSON()
  74. });
  75. // 绑定变化到Mchange
  76. m.bind( 'change', change.noteUpdate, change );
  77. m.bind( 'destroy', change.noteDestroy, change );
  78. }
  79. },
  80. clear: function(){
  81. var i;
  82. for( i = 0; this.models[ i ]; ){
  83. console.log( this.models[ i ].cid );
  84. this.models[ i ].destroy();
  85. }
  86. }
  87. }),
  88. Msync = Backbone.Model.extend({
  89. defaults: {
  90. synced: false,
  91. sync: null,
  92. notes: null,
  93. table: null
  94. },
  95. urlRoot: '/res/sync/',
  96. localStorage: new MODS.localStorageStore( 'sync' ),
  97. initialize: function(){
  98. // 设置notes为私有变量
  99. var Notes = this.get( 'notes' ),
  100. Changes = new CLchange(),
  101. that = this;
  102. this.set({ 'notes': null });
  103. Changes.bindModels( Notes );
  104. // 设置当笔记发生变动时,自动更新记录到同步表中
  105. Notes.bind( 'change', function( m ){
  106. if( !m.get( 'fromServer' ) ){
  107. this.addChange( m, 'update' );
  108. }
  109. }, Changes );
  110. Notes.bind( 'add', function( m ){
  111. if( !m.get( 'fromServer' ) ){
  112. this.addChange( m, 'add' );
  113. }
  114. }, Changes );
  115. Notes.bind( 'remove', function( m ){
  116. this.addChange( m, 'del' );
  117. }, Changes );
  118. // 实时保存
  119. this.bind( 'change', function( m ){
  120. this.save({}, { silent: true });
  121. }, this );
  122. this.getChanges = function(){
  123. return Changes;
  124. };
  125. this.getNotes = function(){
  126. return Notes;
  127. };
  128. this.fetch();
  129. this.save();
  130. },
  131. pushSync: function(){
  132. var that = this;
  133. this.buildSyncTable();
  134. $.ajax({
  135. type: "post",
  136. url: this.urlRoot,
  137. dataType: 'json',
  138. data: JSON.stringify( this.get( 'table' ) ),
  139. success: function( data ){
  140. if( !_.isObject( data ) ){
  141. data = JSON.parse( data );
  142. }
  143. that.updateNotes( data );
  144. // 清理变更记录
  145. that.getChanges().clear();
  146. that.set( { synced: true, sync: Date.now() } );
  147. that.buildSyncTable();
  148. that.save();
  149. },
  150. error: function( err ){
  151. //var data = JSON.parse( err.responseText );
  152. console.log( err.responseText );
  153. }
  154. });
  155. },
  156. /**
  157. * 经从服务器返回的数据更新到models中
  158. * 由于在执行完updateNotes后就回将所有的变更记录清理一遍,因此不用担心更新model的时候又重新添加了变更记录
  159. * @param changeList
  160. */
  161. //todo 要考虑下以_id来进行检查配对数据的情况
  162. //不同登陆序列可能会出现不同的client id 对应相同 _id的情况
  163. //todo 更新还有问题
  164. updateNotes: function( changeList ){
  165. var notes = this.getNotes(),
  166. changes = this.getChanges(),
  167. that = this;
  168. _.each( changeList, function( change ){
  169. var type = change.type,
  170. note = change.note,
  171. id = note.id,
  172. _id = change._id,
  173. clientNote = notes.get( id );
  174. note[ 'fromServer' ] = true;
  175. if( type === 'del' ){
  176. if( clientNote ){
  177. clientNote.destroy();
  178. }
  179. }
  180. else {
  181. if( !clientNote ){
  182. clientNote = notes.create( note );
  183. }
  184. else {
  185. clientNote.set( note );
  186. }
  187. }
  188. if( clientNote ){
  189. clientNote.set( { fromServer: false }, { silent: true } );
  190. clientNote.save( {}, { silent: true } );
  191. }
  192. });
  193. },
  194. buildSyncTable: function(){
  195. var changes = this.getChanges(),
  196. changeList = [],
  197. changeIndex = {},
  198. table;
  199. changes.forEach( function( m, index ){
  200. var note = m.get( 'note' ),
  201. change = {
  202. type: m.get( 'type' ),
  203. date: m.get( 'date' ),
  204. note: note
  205. };
  206. if( note._id !== undefined ){
  207. change._id = note._id;
  208. changeIndex[ note._id ] = index;
  209. }
  210. changeList.push( change );
  211. });
  212. table = {
  213. sync: this.get( 'sync' ),
  214. synced: this.get( 'synced' ),
  215. changeList: changeList,
  216. changeIndex: changeIndex
  217. };
  218. this.set( { 'table': table } );
  219. console.log( this.get( 'table' ) );
  220. return table;
  221. }
  222. });
  223. MODELS[ 'sync' ] = Msync;
  224. MODELS[ 'change' ] = Mchange;
  225. MODELS[ 'changes' ] = CLchange;
  226. })( window[ 'freenote' ] );