2017-02-06 12:40:24 +00:00

313 lines
11 KiB
JavaScript

define(function(require, exports, module) {
main.consumes = [
"Plugin", "remote", "watcher", "fs", "save", "dialog.error", "commands"
];
main.provides = ["HTMLDocument"];
return main;
function main(options, imports, register) {
var Plugin = imports.Plugin;
var remote = imports.remote;
var watcher = imports.watcher;
var save = imports.save;
var fs = imports.fs;
var commands = imports.commands;
var Range = require("ace/range").Range;
var errorDialog = imports["dialog.error"];
var HTMLInstrumentation
= require("../../c9.ide.language.html.diff/HTMLInstrumentation");
function HTMLDocument(path) {
var exists = remote.findDocument(path);
if (exists) return exists;
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
// var emit = plugin.getEmitter();
var transports = [];
var tab, doc, errors = {};
var loaded = false;
function load() {
if (loaded) return false;
loaded = true;
remote.register(plugin);
}
/***** Methods *****/
function addTransport(transport) {
if (transports.indexOf(transport) == -1) {
transports.push(transport);
transport.addOther(function() {
var idx = transports.indexOf(transport);
if (~idx) {
transports.splice(idx, 1);
if (transports.length === 0)
plugin.unload();
}
});
}
if (doc)
initDom(transport);
if (tab && tab.isActive())
updateHighlight(true);
// if (doc && doc.changed)
// update();
return plugin;
}
function initTab(t) {
if (!t) {
doc = null;
if (tab) {
fs.readFile(path, function(err, data) {
update(null, data);
});
}
tab = null;
return;
}
tab = t;
doc = tab.document;
// Listen for change in the document
var c9session = doc.getSession();
c9session.once("init", function(e) {
e.session.on("change", update);
e.session.selection.on("changeCursor", updateHighlight);
e.session.savedDom = null;
e.session.dom = null;
e.session.htmldocument = plugin;
plugin.addOther(function () {
e.session.off("change", update);
e.session.selection.off("changeCursor", updateHighlight);
e.session.savedDom = null;
e.session.dom = null;
e.session.htmldocument = null;
});
transports.forEach(function(transport) {
initDom(transport, doc);
});
});
tab.editor.ace.on("focus", function() { updateHighlight(true); }, plugin);
tab.on("activate", function() { updateHighlight(); }, plugin);
tab.on("deactivate", function() { updateHighlight(false); }, plugin);
// Listen for a tab close event
tab.on("close", function() { watcher.watch(path); });
// @Ruben is there a better way to listen for save event?
save.on("afterSave", function(e) {
if (e.document == doc) {
var session = doc.getSession().session;
if (session) {
if (!session.dom && !session.savedDom && errors.save) {
errors.save = false;
transports.forEach(function(transport) {
transport.reload();
});
}
session.savedDom = session.dom;
}
}
}, plugin);
}
function initDom(transport) {
if (!doc) return;
var session = doc.getSession().session;
if (!session) return;
var docState = HTMLInstrumentation.syncTagIds(session);
if (!session.dom && docState.errors) {
var editList = HTMLInstrumentation.getUnappliedEditList(session);
if (!reportErrors(session, editList)) {
errors.save = true;
var name = doc.tab.path && doc.tab.path.match(/(^|\/)([^\/]*)$/)[2] || "the document";
errorDialog.show("Please save " + name + " to start a new live editing session");
}
}
if (docState.errors) {
session.dom = null;
this.errors = docState.errors;
console.log(this.errors);
} else {
transport.initHTMLDocument(docState);
}
}
function updateHighlight(e) {
var query, tagId;
if (tab && e !== false) {
var session = doc.getSession().session;
if (!session || !session.dom) return;
var pos = {
row: session.selection.lead.row,
column: session.selection.lead.column
};
if (session.doc.getLine(pos.row)[pos.column] === "<")
pos.column++; // prefer element after cursor
tagId = HTMLInstrumentation._getTagIDAtDocumentPos(session, pos);
}
if (tagId) {
query = "[data-cloud9-id='" + tagId + "']";
} else {
query = false;
}
// Send the highlight command
transports.forEach(function(transport) {
transport.highlightCSSQuery(query, e === true);
});
}
function update(changes, value) {
if (!changes) return; //@todo allow only value to be set
// Calculate changes
var session = doc.getSession().session;
if (!session.dom) {
transports.forEach(function(transport) {
initDom(transport);
});
return;
}
var result = HTMLInstrumentation.getUnappliedEditList(session, changes);
if (result.edits && result.edits.length) {
transports.forEach(function(transport) {
transport.processDOMChanges(result.edits, path);
});
}
reportErrors(session, result);
}
function reportErrors(session, editList) {
if (!editList.edits && editList.errors && editList.errors.length) {
scheduleDisplayError("Unable to update preview: unmatched tags detected");
} else {
scheduleDisplayError(false);
}
errors.unmatchedTags = editList.errors;
if (session.domErrorMarker) {
session.removeMarker(session.domErrorMarker);
session.domErrorMarker = null;
}
if (errors.unmatchedTags && errors.unmatchedTags.length) {
var error = errors.unmatchedTags[0];
var range = Range.fromPoints(error.startPos, error.endPos);
if (range.isEmpty()) {
range.start.column--;
range.end.column++;
}
session.domErrorMarker = session.addMarker(range, "language_highlight_error", "text");
}
return editList.errors && editList.errors.length;
}
function scheduleDisplayError(msg) {
clearTimeout(errors.timer);
if (!msg && !errors.msg) return;
errors.timer = setTimeout(function() {
errors.msg = msg;
errorDialog.show(msg, 2000);
}, 800);
}
function scrollIntoView() {
updateHighlight();
transports.forEach(function(transport) {
transport.reveal();
});
}
/***** Lifecycle *****/
plugin.on("load", function() {
load();
});
plugin.on("enable", function() {
});
plugin.on("disable", function() {
});
plugin.on("unload", function() {
loaded = false;
});
/***** Register and define API *****/
/**
*
**/
plugin.freezePublicAPI({
/**
*
*/
get path() { return path; },
/**
*
*/
get tab() { return tab; },
/**
*
*/
set tab(tab) { initTab(tab); },
_events: [
/**
* @event draw
*/
"draw"
],
/**
*
*/
addTransport: addTransport,
/**
*
*/
update: update,
/**
*
*/
scrollIntoView: scrollIntoView
});
plugin.load(null, "htmldocument");
return plugin;
}
register(null, {
HTMLDocument: HTMLDocument
});
}
});