PageRenderTime 26ms CodeModel.GetById 38ms RepoModel.GetById 7ms app.codeStats 0ms

/static-content/frontend/filerenderer.ts

https://github.com/Twinside/DiffTimeline
TypeScript | 246 lines | 186 code | 53 blank | 7 comment | 72 complexity | ccffd9ff070ba9a3ec62c34fc5fd3063 MD5 | raw file
  1. /// <reference path="resultset.ts" />
  2. /// <reference path="linealign.ts" />
  3. /// <reference path="diffmanipulator.ts" />
  4. /// <reference path="difftimeline.extern.ts" />
  5. /// <reference path="resultset.ts" />
  6. /// <reference path="project.ts" />
  7. /// <reference path="fileblob.ts" />
  8. class KeyAssocs
  9. {
  10. [ix: string] : FileBlob;
  11. };
  12. class FileRenderer implements ResultSet
  13. {
  14. private collection : FileBlob[];
  15. private keys : KeyAssocs;
  16. private focused_index : number;
  17. private fetching : boolean;
  18. private aligner : FileAlign;
  19. public constructor(init_data : ParentFile) {
  20. var init_file = new FileBlob(init_data);
  21. this.collection = [];
  22. this.keys = new KeyAssocs();
  23. this.focused_index = 0;
  24. this.fetching = false;
  25. this.collection = [init_file];
  26. this.keys[init_file.key] = init_file;
  27. var new_node = init_file.create_dom();
  28. this.insert_node( new_node );
  29. this.aligner = new FileAlign();
  30. $(new_node).addClass(global_focus);
  31. init_file.render([]);
  32. return this;
  33. }
  34. private static fetch_file(file: string,
  35. commit : Ref,
  36. filekey : any,
  37. f: (data: ParentFile | ErrorReturn) => void) {
  38. var request = '/ask_parent/' + commit;
  39. if (file[0] == '/')
  40. file = file.substring(1);
  41. request += '/' + encodeURIComponent(file);
  42. $.ajax({ url: request, dataType: 'json',
  43. error: function() {
  44. show_error({error: 'Communication error with the server while fetching file'});
  45. },
  46. success: f });
  47. }
  48. public insert_node(node: Element | JQuery) {
  49. $(".container").prepend( node );
  50. }
  51. public create_all_dom() {
  52. for ( var i = this.collection.length - 1; i >= 0; i-- ) {
  53. this.insert_node(this.collection[i].create_dom());
  54. }
  55. }
  56. public render_all() {
  57. for ( var i = 0; i < this.collection.length - 1; i++ ) {
  58. this.collection[i].render(this.collection[i + 1].diff);
  59. }
  60. this.collection[i].render([]);
  61. }
  62. public fetch_details(commit_id : Ref) {
  63. this.keys[commit_id].fetch_details();
  64. }
  65. public move_left() {
  66. $(this.collection[this.focused_index].orig_node).removeClass(global_focus);
  67. if (this.focused_index === 0) {
  68. this.fetch_previous(0);
  69. return;
  70. }
  71. this.focused_index--;
  72. var new_focused_node = this.collection[this.focused_index].orig_node;
  73. $(new_focused_node).addClass(global_focus);
  74. this.collection[this.focused_index].focus_line(200);
  75. }
  76. public move_right() {
  77. if (this.focused_index === this.collection.length - 1)
  78. return;
  79. $(this.collection[this.focused_index].orig_node).removeClass(global_focus);
  80. this.focused_index++;
  81. var new_focused_node = this.collection[this.focused_index].orig_node;
  82. $(new_focused_node).addClass(global_focus);
  83. this.collection[this.focused_index].focus_line(200);
  84. }
  85. public synchronize_lines( targetted_line : number ) {
  86. var i : number;
  87. var curr_index = this.focused_index;
  88. var max_idx = this.collection.length;
  89. var matching_lines : number[] = new Array( max_idx );
  90. matching_lines[curr_index] = targetted_line;
  91. for (i = curr_index; i < max_idx - 1; i++) {
  92. matching_lines[i + 1] =
  93. this.collection[i + 1].compute_matching_line_from_past(matching_lines[i]);
  94. }
  95. for (i = curr_index; i > 0; i--) {
  96. matching_lines[i - 1] =
  97. this.collection[i].compute_matching_line_from_future(matching_lines[i]);
  98. }
  99. var max_line = Math.max.apply(Math, matching_lines);
  100. for (i = 0; i < max_idx; i++) {
  101. let blob = this.collection[i];
  102. blob.set_line_offset(max_line - matching_lines[i]);
  103. blob.set_line(matching_lines[i]);
  104. }
  105. this.collection[ curr_index ].focus_line(5);
  106. }
  107. public move_line_up() {
  108. var curr = this.collection[this.focused_index];
  109. this.synchronize_lines(curr.move_line_up());
  110. }
  111. public move_line_down() {
  112. var curr = this.collection[this.focused_index];
  113. this.synchronize_lines(curr.move_line_down());
  114. }
  115. public send_message( msg : GuiMessage ) : any {
  116. if (msg.action === Project.GuiMessageCode.FETCH_DETAIL)
  117. return this.fetch_details((msg as any).key);
  118. else if (msg.action === Project.GuiMessageCode.MOVE_LEFT)
  119. return this.move_left();
  120. else if (msg.action === Project.GuiMessageCode.MOVE_RIGHT)
  121. return this.move_right();
  122. else if (msg.action === Project.GuiMessageCode.MOVE_DOWN)
  123. return this.move_line_down();
  124. else if (msg.action === Project.GuiMessageCode.MOVE_UP)
  125. return this.move_line_up();
  126. else if (msg.action === Project.GuiMessageCode.COMMAND_REQUEST) {
  127. var this_obj = this;
  128. var abs = function (line : number) {
  129. var curr = this_obj.collection[this_obj.focused_index];
  130. this_obj.synchronize_lines(curr.set_line(line));
  131. };
  132. var rel = function (offset : number) {
  133. var curr = this_obj.collection[this_obj.focused_index];
  134. this_obj.synchronize_lines(curr.offset_line(offset));
  135. };
  136. return this.aligner.command_request(abs, rel);
  137. }
  138. else if (msg.action === Project.GuiMessageCode.SELECT_AS_LEFT)
  139. this.collection[this.focused_index].select_as_left();
  140. else if (msg.action === Project.GuiMessageCode.SELECT_AS_RIGHT)
  141. this.collection[this.focused_index].select_as_right();
  142. else if (msg.action === Project.GuiMessageCode.SWITCH_BLAME)
  143. this.collection[this.focused_index].switch_blame();
  144. }
  145. public fetch_previous(id : number) {
  146. var last_commit = this.collection[0];
  147. var this_obj = this;
  148. if (this.fetching) return;
  149. if (last_commit.parent_commit.length <= 0) {
  150. show_error( {error: "The commit has no parents"});
  151. return;
  152. }
  153. var to_fetch = last_commit.parent_commit[id].key;
  154. this_obj.fetching = true;
  155. FileRenderer.fetch_file(last_commit.file, to_fetch,
  156. last_commit.filekey, function(data) {
  157. if (data === null) {
  158. show_error({error: 'Communication error with the server'});
  159. return;
  160. }
  161. if (data.hasOwnProperty('error')) {
  162. show_error( data as ErrorReturn );
  163. return;
  164. }
  165. var new_commit = new FileBlob(data as ParentFile);
  166. var node = new_commit.create_dom();
  167. this_obj.insert_node(node);
  168. this_obj.collection.unshift( new_commit );
  169. this_obj.focused_index++;
  170. this_obj.keys[new_commit.key] = new_commit;
  171. node.animate({'width': 'toggle'}, 0);
  172. this_obj.collection[0].render(this_obj.collection[1].diff);
  173. node.animate({'width': 'toggle'}, Project.state.apparition_duration() * 2);
  174. this_obj.move_left();
  175. this_obj.fetching = false;
  176. });
  177. }
  178. public static create_from_data(init_data : ParentFile) {
  179. return new FileRenderer(init_data);
  180. }
  181. public static create_from_arg(file : string,
  182. filekey : any,
  183. commit : Ref,
  184. callback : (fr : FileRenderer) => void) {
  185. FileRenderer.fetch_file(file, commit, filekey, function(data : ParentFile) {
  186. data.file = file;
  187. callback( new FileRenderer(data) );
  188. });
  189. }
  190. public gui_descr =
  191. { compact_view: true, fetch_previous: true
  192. , context_size: true, syntax_toggle: false };
  193. }