Switch to ACE editor

This commit is contained in:
benweet 2013-09-11 00:51:37 +01:00
parent 23dcda3cf4
commit 4a9b286fc0
4 changed files with 92 additions and 67 deletions

View File

@ -455,8 +455,6 @@ define([
eventMgr.onPagedownConfigure(editor); eventMgr.onPagedownConfigure(editor);
editor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview); editor.hooks.chain("onPreviewRefresh", eventMgr.onAsyncPreview);
editor.run(aceEditor, previewWrapper); editor.run(aceEditor, previewWrapper);
// editor.undoManager.reinit(initDocumentContent, fileDesc.editorStart,
// fileDesc.editorEnd, fileDesc.editorScrollTop);
aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange); aceEditor.selection.setSelectionRange(fileDesc.editorSelectRange);
aceEditor.focus(); aceEditor.focus();

View File

@ -1320,6 +1320,14 @@
var inputBox = panels.input, var inputBox = panels.input,
buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements. buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements.
this.setUndoRedoButtonStates = function() {
setTimeout(function() {
setupButton(buttons.undo, inputBox.session.getUndoManager().hasUndo());
setupButton(buttons.redo, inputBox.session.getUndoManager().hasRedo());
}, 50);
};
var that = this;
makeSpritedButtonRow(); makeSpritedButtonRow();
var keyEvent = "keydown"; var keyEvent = "keydown";
@ -1641,24 +1649,12 @@
buttons.help = helpButton; buttons.help = helpButton;
} }
setUndoRedoButtonStates(); that.setUndoRedoButtonStates();
inputBox.session.on('change', setUndoRedoButtonStates); inputBox.session.on('change', function() {
that.setUndoRedoButtonStates();
});
} }
function setUndoRedoButtonStates() {
/*benweet
if (undoManager) {
setupButton(buttons.undo, undoManager.canUndo());
setupButton(buttons.redo, undoManager.canRedo());
}
*/
setTimeout(function() {
setupButton(buttons.undo, inputBox.session.getUndoManager().hasUndo());
setupButton(buttons.redo, inputBox.session.getUndoManager().hasRedo());
}, 0);
};
this.setUndoRedoButtonStates = setUndoRedoButtonStates;
this.buttons = buttons; this.buttons = buttons;
this.setButtonState = setupButton; this.setButtonState = setupButton;

View File

@ -132,17 +132,9 @@ define([
}; };
gdriveProvider.syncUpRealtime = function(uploadContent, uploadContentCRC, uploadTitle, uploadTitleCRC, syncAttributes, callback) { gdriveProvider.syncUpRealtime = function(uploadContent, uploadContentCRC, uploadTitle, uploadTitleCRC, syncAttributes, callback) {
var uploadFlag = false;
if(uploadContentCRC != syncAttributes.contentCRC) {
// We don't upload the content since it's a realtime file
syncAttributes.contentCRC = uploadContentCRC;
// But we still inform synchronizer to update syncAttributes
uploadFlag = true;
}
// Skip if title CRC has not changed // Skip if title CRC has not changed
if(uploadTitleCRC == syncAttributes.titleCRC) { if(uploadTitleCRC == syncAttributes.titleCRC) {
callback(undefined, uploadFlag); callback(undefined, false);
return; return;
} }
googleHelper.rename(syncAttributes.id, uploadTitle, function(error, result) { googleHelper.rename(syncAttributes.id, uploadTitle, function(error, result) {
@ -272,17 +264,36 @@ define([
return publishAttributes; return publishAttributes;
}; };
// Keep a link to the pagedown editor // Keep a link to the Pagedown editor
var editor = undefined; var pagedownEditor = undefined;
eventMgr.addListener("onPagedownConfigure", function(editorParam) { eventMgr.addListener("onPagedownConfigure", function(pagedownEditorParam) {
editor = editorParam; pagedownEditor = pagedownEditorParam;
}); });
// Start realtime synchronization // Start realtime synchronization
var realtimeDocument = undefined; var realtimeDocument = undefined;
var realtimeBinding = undefined; var realtimeString = undefined;
var undoExecute = undefined; var undoExecute = undefined;
var redoExecute = undefined; var redoExecute = undefined;
var setUndoRedoButtonStates = undefined;
// Keep a link to the ACE editor
var aceEditor = undefined;
var isAceUpToDate = false;
eventMgr.addListener('onAceCreated', function(aceEditorParam) {
aceEditor = aceEditorParam;
// Listen to editor's changes
aceEditor.session.on('change', function(e) {
if(realtimeString !== undefined) {
// Update the real time model]
// The flag is used to avoid replaying editor's own modifications (assuming it's synchronous)
isAceUpToDate = true;
realtimeString.setText(aceEditor.getValue());
isAceUpToDate = false;
}
});
});
var Range = require('ace/range').Range;
gdriveProvider.startRealtimeSync = function(fileDesc, syncAttributes) { gdriveProvider.startRealtimeSync = function(fileDesc, syncAttributes) {
googleHelper.loadRealtime(syncAttributes.id, fileDesc.content, function(err, doc) { googleHelper.loadRealtime(syncAttributes.id, fileDesc.content, function(err, doc) {
if(err || !doc) { if(err || !doc) {
@ -298,27 +309,46 @@ define([
logger.log("Starting Google Drive realtime synchronization"); logger.log("Starting Google Drive realtime synchronization");
realtimeDocument = doc; realtimeDocument = doc;
var model = realtimeDocument.getModel(); var model = realtimeDocument.getModel();
var string = model.getRoot().get('content'); realtimeString = model.getRoot().get('content');
// Saves model content checksum // Saves model content checksum
function updateContentState() { function updateContentState() {
syncAttributes.contentCRC = utils.crc32(string.getText()); syncAttributes.contentCRC = utils.crc32(realtimeString.getText());
utils.storeAttributes(syncAttributes); utils.storeAttributes(syncAttributes);
} }
var debouncedRefreshPreview = _.debounce(editor.refreshPreview, 100); // Listen to insert text events
// Called when a modification has been detected realtimeString.addEventListener(gapi.drive.realtime.EventType.TEXT_INSERTED, function(e) {
function contentChangeListener(e) { if(isAceUpToDate === true) {
// If modification comes down from a collaborator // Don't need to update ACE if modifications come from the editor
return;
}
// Update ACE editor
var position = aceEditor.session.doc.indexToPosition(e.index);
aceEditor.session.insert(position, e.text);
// If modifications come down from a collaborator
if(e.isLocal === false) { if(e.isLocal === false) {
logger.log("Google Drive realtime document updated from server"); logger.log("Google Drive realtime document updated from server");
updateContentState(); updateContentState();
debouncedRefreshPreview();
} }
});
// Listen to delete text events
realtimeString.addEventListener(gapi.drive.realtime.EventType.TEXT_DELETED, function(e) {
if(isAceUpToDate === true) {
// Don't need to update ACE if modifications come from the editor
return;
} }
// Listen to text changed events // Update ACE editor
string.addEventListener(gapi.drive.realtime.EventType.TEXT_INSERTED, contentChangeListener); var range = (function(posStart, posEnd) {
string.addEventListener(gapi.drive.realtime.EventType.TEXT_DELETED, contentChangeListener); return new Range(posStart.row, posStart.column, posEnd.row, posEnd.column);
})(aceEditor.session.doc.indexToPosition(e.index), aceEditor.session.doc.indexToPosition(e.index + e.text.length));
aceEditor.session.remove(range);
// If modifications come down from a collaborator
if(e.isLocal === false) {
logger.log("Google Drive realtime document updated from server");
updateContentState();
}
});
realtimeDocument.addEventListener(gapi.drive.realtime.EventType.DOCUMENT_SAVE_STATE_CHANGED, function(e) { realtimeDocument.addEventListener(gapi.drive.realtime.EventType.DOCUMENT_SAVE_STATE_CHANGED, function(e) {
// Save success event // Save success event
if(e.isPending === false && e.isSaving === false) { if(e.isPending === false && e.isSaving === false) {
@ -330,7 +360,7 @@ define([
// Try to merge offline modifications // Try to merge offline modifications
var localContent = fileDesc.content; var localContent = fileDesc.content;
var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent); var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent);
var remoteContent = string.getText(); var remoteContent = realtimeString.getText();
var remoteContentCRC = utils.crc32(remoteContent); var remoteContentCRC = utils.crc32(remoteContent);
var remoteContentChanged = syncAttributes.contentCRC != remoteContentCRC; var remoteContentChanged = syncAttributes.contentCRC != remoteContentCRC;
var fileContentChanged = localContent != remoteContent; var fileContentChanged = localContent != remoteContent;
@ -342,39 +372,40 @@ define([
} }
else { else {
// Add local modifications if no collaborators change // Add local modifications if no collaborators change
string.setText(localContent); realtimeString.setText(localContent);
} }
} }
// Binds model with textarea
realtimeBinding = gapi.drive.realtime.databinding.bindString(string, document.getElementById("wmd-input"));
// Update content state according to collaborators changes // Update content state according to collaborators changes
if(remoteContentChanged === true) { if(remoteContentChanged === true) {
logger.log("Google Drive realtime document updated from server"); logger.log("Google Drive realtime document updated from server");
aceEditor.setValue(remoteContent);
updateContentState(); updateContentState();
debouncedRefreshPreview();
} }
// Save undo/redo buttons actions // Save undo/redo buttons actions
undoExecute = editor.uiManager.buttons.undo.execute; undoExecute = pagedownEditor.uiManager.buttons.undo.execute;
redoExecute = editor.uiManager.buttons.redo.execute; redoExecute = pagedownEditor.uiManager.buttons.redo.execute;
setUndoRedoButtonStates = pagedownEditor.uiManager.setUndoRedoButtonStates;
// Set new actions for undo/redo buttons // Set new actions for undo/redo buttons
editor.uiManager.buttons.undo.execute = function() { pagedownEditor.uiManager.buttons.undo.execute = function() {
model.canUndo && model.undo(); model.canUndo && model.undo();
}; };
editor.uiManager.buttons.redo.execute = function() { pagedownEditor.uiManager.buttons.redo.execute = function() {
model.canRedo && model.redo(); model.canRedo && model.redo();
}; };
// Add event handler for model's UndoRedoStateChanged events // Add event handler for model's UndoRedoStateChanged events
function setUndoRedoState() { pagedownEditor.uiManager.setUndoRedoButtonStates = function() {
editor.uiManager.setButtonState(editor.uiManager.buttons.undo, model.canUndo); setTimeout(function() {
editor.uiManager.setButtonState(editor.uiManager.buttons.redo, model.canRedo); pagedownEditor.uiManager.setButtonState(pagedownEditor.uiManager.buttons.undo, model.canUndo);
} pagedownEditor.uiManager.setButtonState(pagedownEditor.uiManager.buttons.redo, model.canRedo);
model.addEventListener(gapi.drive.realtime.EventType.UNDO_REDO_STATE_CHANGED, setUndoRedoState); }, 50);
setUndoRedoState(); };
pagedownEditor.uiManager.setUndoRedoButtonStates();
model.addEventListener(gapi.drive.realtime.EventType.UNDO_REDO_STATE_CHANGED, function() {
pagedownEditor.uiManager.setUndoRedoButtonStates();
});
}, function(err) { }, function(err) {
console.error(err); console.error(err);
@ -397,9 +428,8 @@ define([
// Stop realtime synchronization // Stop realtime synchronization
gdriveProvider.stopRealtimeSync = function() { gdriveProvider.stopRealtimeSync = function() {
logger.log("Stopping Google Drive realtime synchronization"); logger.log("Stopping Google Drive realtime synchronization");
if(realtimeBinding !== undefined) { if(realtimeString !== undefined) {
realtimeBinding.unbind(); realtimeString = undefined;
realtimeBinding = undefined;
} }
if(realtimeDocument !== undefined) { if(realtimeDocument !== undefined) {
realtimeDocument.close(); realtimeDocument.close();
@ -407,9 +437,10 @@ define([
} }
// Set back original undo/redo actions // Set back original undo/redo actions
editor.uiManager.buttons.undo.execute = undoExecute; pagedownEditor.uiManager.buttons.undo.execute = undoExecute;
editor.uiManager.buttons.redo.execute = redoExecute; pagedownEditor.uiManager.buttons.redo.execute = redoExecute;
editor.uiManager.setUndoRedoButtonStates(); pagedownEditor.uiManager.setUndoRedoButtonStates = setUndoRedoButtonStates;
pagedownEditor.uiManager.setUndoRedoButtonStates();
}; };
eventMgr.addListener("onReady", function() { eventMgr.addListener("onReady", function() {

View File

@ -295,7 +295,7 @@ define([
// Save As menu items // Save As menu items
$(".action-download-md").click(function() { $(".action-download-md").click(function() {
var content = document.getElementById("wmd-input").value; var content = fileMgr.currentFile.content;
var title = fileMgr.currentFile.title; var title = fileMgr.currentFile.title;
utils.saveAs(content, title + ".md"); utils.saveAs(content, title + ".md");
}); });