Advertisement
Guest User

ace.js

a guest
Sep 16th, 2020
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.77 KB | None | 0 0
  1. // Connect to the domain. See ../config.js for the connection settings.
  2.  
  3. const username = "DEMOUSER";
  4.  
  5. Convergence.connectAnonymously(CONVERGENCE_URL, username)
  6. .then(d => {
  7. domain = d;
  8. // Now open the model, creating it using the initial data if it does not exist.
  9. return domain.models().openAutoCreate({
  10. collection: "example-ace",
  11. id: "f84cc077-8897-4082-90a6-43660ede3c8c",
  12. ephemeral: true,
  13. data: {text: defaultEditorContents}
  14. })
  15. })
  16. .then(handleOpen)
  17. .catch(error => {
  18. console.error("Could not open model ", error);
  19. });
  20.  
  21. const AceRange = ace.require("ace/range").Range;
  22.  
  23. const colorAssigner = new ConvergenceColorAssigner.ColorAssigner();
  24.  
  25. let editor = null;
  26. let session = null;
  27. let doc = null;
  28.  
  29. function handleOpen(model) {
  30. editor = ace.edit("ace-editor");
  31. editor.setTheme('ace/theme/monokai');
  32.  
  33. session = editor.getSession();
  34. session.setMode('ace/mode/javascript');
  35.  
  36. doc = session.getDocument();
  37.  
  38. const textModel = model.elementAt("text");
  39.  
  40. initModel(textModel);
  41. initSharedCursors(textModel);
  42. initSharedSelection(textModel);
  43.  
  44. const radarViewElement = document.getElementById("radar-view");
  45. initRadarView(textModel, radarViewElement);
  46. }
  47.  
  48. /////////////////////////////////////////////////////////////////////////////
  49. // Text Binding
  50. /////////////////////////////////////////////////////////////////////////////
  51. let suppressEvents = false;
  52.  
  53. function initModel(textModel) {
  54. const session = editor.getSession();
  55. session.setValue(textModel.value());
  56.  
  57. textModel.on("insert", (e) => {
  58. const pos = doc.indexToPosition(e.index);
  59. suppressEvents = true;
  60. doc.insert(pos, e.value);
  61. suppressEvents = false;
  62. });
  63.  
  64. textModel.on("remove", (e) => {
  65. const start = doc.indexToPosition(e.index);
  66. const end = doc.indexToPosition(e.index + e.value.length);
  67. suppressEvents = true;
  68. doc.remove(new AceRange(start.row, start.column, end.row, end.column));
  69. suppressEvents = false;
  70. });
  71.  
  72. textModel.on("value", function (e) {
  73. suppressEvents = true;
  74. doc.setValue(e.value);
  75. suppressEvents = false;
  76. });
  77.  
  78. editor.on('change', (delta) => {
  79. if (suppressEvents) {
  80. return;
  81. }
  82.  
  83. const pos = doc.positionToIndex(delta.start);
  84. switch (delta.action) {
  85. case "insert":
  86. textModel.insert(pos, delta.lines.join("\n"));
  87. break;
  88. case "remove":
  89. textModel.remove(pos, delta.lines.join("\n").length);
  90. break;
  91. default:
  92. throw new Error("unknown action: " + delta.action);
  93. }
  94. });
  95. }
  96.  
  97. /////////////////////////////////////////////////////////////////////////////
  98. // Cursor Binding
  99. /////////////////////////////////////////////////////////////////////////////
  100. const cursorKey = "cursor";
  101. let cursorReference = null;
  102. let cursorManager = null;
  103.  
  104. function initSharedCursors(textElement) {
  105. cursorManager = new AceCollabExt.AceMultiCursorManager(editor.getSession());
  106. cursorReference = textElement.indexReference(cursorKey);
  107.  
  108. const references = textElement.references({key: cursorKey});
  109. references.forEach((reference) => {
  110. if (!reference.isLocal()) {
  111. addCursor(reference);
  112. }
  113. });
  114.  
  115. setLocalCursor();
  116. cursorReference.share();
  117.  
  118. editor.getSession().selection.on('changeCursor', () => setLocalCursor());
  119.  
  120. textElement.on("reference", (e) => {
  121. if (e.reference.key() === cursorKey) {
  122. this.addCursor(e.reference);
  123. }
  124. });
  125. }
  126.  
  127. function setLocalCursor() {
  128. const position = editor.getCursorPosition();
  129. const index = doc.positionToIndex(position);
  130. cursorReference.set(index);
  131. }
  132.  
  133. function addCursor(reference) {
  134. const color = colorAssigner.getColorAsHex(reference.sessionId());
  135. const remoteCursorIndex = reference.value();
  136. cursorManager.addCursor(reference.sessionId(), reference.user().displayName, color, remoteCursorIndex);
  137.  
  138. reference.on("cleared", () => cursorManager.clearCursor(reference.sessionId()));
  139. reference.on("disposed", () => cursorManager.removeCursor(reference.sessionId()));
  140. reference.on("set", () => {
  141. const cursorIndex = reference.value();
  142. const cursorRow = doc.indexToPosition(cursorIndex).row;
  143. cursorManager.setCursor(reference.sessionId(), cursorIndex);
  144.  
  145. if (radarView.hasView(reference.sessionId())) {
  146. radarView.setCursorRow(reference.sessionId(), cursorRow);
  147. }
  148. });
  149. }
  150.  
  151. /////////////////////////////////////////////////////////////////////////////
  152. // Selection Binding
  153. /////////////////////////////////////////////////////////////////////////////
  154. let selectionManager = null;
  155. let selectionReference = null;
  156. const selectionKey = "selection";
  157.  
  158. function initSharedSelection(textModel) {
  159. selectionManager = new AceCollabExt.AceMultiSelectionManager(editor.getSession());
  160.  
  161. selectionReference = textModel.rangeReference(selectionKey);
  162. setLocalSelection();
  163. selectionReference.share();
  164.  
  165. session.selection.on('changeSelection', () => setLocalSelection());
  166.  
  167. const references = textModel.references({key: selectionKey});
  168. references.forEach((reference) => {
  169. if (!reference.isLocal()) {
  170. addSelection(reference);
  171. }
  172. });
  173.  
  174. textModel.on("reference", (e) => {
  175. if (e.reference.key() === selectionKey) {
  176. addSelection(e.reference);
  177. }
  178. });
  179. }
  180.  
  181. function setLocalSelection() {
  182. if (!editor.selection.isEmpty()) {
  183. const aceRanges = editor.selection.getAllRanges();
  184. const indexRanges = aceRanges.map((aceRagne) => {
  185. const start = doc.positionToIndex(aceRagne.start);
  186. const end = doc.positionToIndex(aceRagne.end);
  187. return {start: start, end: end};
  188. });
  189.  
  190. selectionReference.set(indexRanges);
  191. } else if (selectionReference.isSet()) {
  192. selectionReference.clear();
  193. }
  194. }
  195.  
  196. function addSelection(reference) {
  197. const color = colorAssigner.getColorAsHex(reference.sessionId());
  198. const remoteSelection = reference.values().map(range => toAceRange(range));
  199. selectionManager.addSelection(reference.sessionId(), reference.user().username, color, remoteSelection);
  200.  
  201. reference.on("cleared", () => selectionManager.clearSelection(reference.sessionId()));
  202. reference.on("disposed", () => selectionManager.removeSelection(reference.sessionId()));
  203. reference.on("set", () => {
  204. selectionManager.setSelection(
  205. reference.sessionId(), reference.values().map(range => toAceRange(range)));
  206. });
  207. }
  208.  
  209. function toAceRange(range) {
  210. if (typeof range !== 'object') {
  211. return null;
  212. }
  213.  
  214. let start = range.start;
  215. let end = range.end;
  216.  
  217. if (start > end) {
  218. const temp = start;
  219. start = end;
  220. end = temp;
  221. }
  222.  
  223. const rangeAnchor = doc.indexToPosition(start);
  224. const rangeLead = doc.indexToPosition(end);
  225. return new AceRange(rangeAnchor.row, rangeAnchor.column, rangeLead.row, rangeLead.column);
  226. }
  227.  
  228. /////////////////////////////////////////////////////////////////////////////
  229. // Radar View Binding
  230. /////////////////////////////////////////////////////////////////////////////
  231. let radarView = null;
  232. let viewReference = null;
  233. const viewKey = "view";
  234.  
  235. function initRadarView(textModel, radarViewElement) {
  236. radarView = new AceCollabExt.AceRadarView(radarViewElement, editor);
  237. viewReference = textModel.rangeReference(viewKey);
  238.  
  239. const references = textModel.references({key: viewKey});
  240. references.forEach((reference) => {
  241. if (!reference.isLocal()) {
  242. addView(reference);
  243. }
  244. });
  245.  
  246. session.on('changeScrollTop', () => {
  247. setTimeout(() => setLocalView(), 0);
  248. });
  249.  
  250. textModel.on("reference", (e) => {
  251. if (e.reference.key() === viewKey) {
  252. addView(e.reference);
  253. }
  254. });
  255.  
  256. setTimeout(() => {
  257. setLocalView();
  258. viewReference.share();
  259. }, 0);
  260. }
  261.  
  262. function setLocalView() {
  263. const viewportIndices = AceCollabExt.AceViewportUtil.getVisibleIndexRange(editor);
  264. viewReference.set({start: viewportIndices.start, end: viewportIndices.end});
  265. }
  266.  
  267. function addView(reference) {
  268. const color = colorAssigner.getColorAsHex(reference.sessionId());
  269.  
  270. // fixme need the cursor
  271. let cursorRow = null;
  272. let viewRows = null;
  273.  
  274. if (reference.isSet()) {
  275. const remoteViewIndices = reference.value();
  276. viewRows = AceCollabExt.AceViewportUtil.indicesToRows(editor, remoteViewIndices.start, remoteViewIndices.end);
  277. }
  278.  
  279. radarView.addView(reference.sessionId(), reference.user().username, color, viewRows, cursorRow);
  280.  
  281. // fixme need to implement this on the ace collab side
  282. reference.on("cleared", () => radarView.clearView(reference.sessionId()));
  283. reference.on("disposed", () => radarView.removeView(reference.sessionId()));
  284. reference.on("set", () => {
  285. const v = reference.value();
  286. const rows = AceCollabExt.AceViewportUtil.indicesToRows(editor, v.start, v.end);
  287. radarView.setViewRows(reference.sessionId(), rows);
  288. });
  289. }
  290.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement