oxjs/source/Ox.UI/js/Core/Ox.SyntaxHighlighter.js

136 lines
4.4 KiB
JavaScript
Raw Normal View History

// vim: et:ts=4:sw=4:sts=4:ft=js
/*@
@*/
Ox.SyntaxHighlighter = function(options, self) {
self = self || {};
2011-04-29 12:40:51 +00:00
var that = new Ox.Element({}, self)
.defaults({
height: 40,
lineLength: 80, //@ number of characters per line
showLinebreaks: false, //@ show linebreak symbols
showTabs: false, //@ show tab symbols
showWhitespace: false, //@ show irregular leading or trailing whitespace
source: '', //@ JavaScript source
stripComments: false, //@ strip all comments
stripLinebreaks: false, //@ strip multiple linebreaks, NOT IMPLEMENTED
stripWhitespace: false, //@ strip all whitespace, NOT IMPLEMENTED
tabLength: 4, //@ number of spaces per tab
width: 80
})
.options(options || {})
.addClass('OxSyntaxHighlighter');
var foo = $('<div>')
//.css({marginTop: '-1000px'})
.html(Ox.repeat('_', 80))
.appendTo(that.$element);
//alert(foo.width());
foo.remove();
self.options.source = self.options.source
.replace(/\r\n/g, '\n')
.replace(/\r/g, '\n');
self.cursor = 0;
self.source = '';
self.tokens = Ox.tokenize(self.options.source);
self.tokens.forEach(function(token, i) {
2011-05-05 18:02:56 +00:00
var classNames;
if (
!(self.options.stripComments && token.type == 'comment')
) {
classNames = 'Ox' + Ox.toTitleCase(token.type);
if (token.type == 'whitespace') {
if (isAfterLinebreak() && hasIrregularSpaces()) {
classNames += ' OxLeading'
} else if (isBeforeLinebreak()) {
classNames += ' OxTrailing'
}
}
self.source += '<span class="' + classNames + '">' +
2011-05-05 18:02:56 +00:00
encodeToken(token.source, token.type) + '</span>';
}
self.cursor += token.length;
function isAfterLinebreak() {
return i == 0 ||
self.tokens[i - 1].type == 'linebreak';
}
function isBeforeLinebreak() {
return i == self.tokens.length - 1 ||
self.tokens[i + 1].type == 'linebreak';
}
function hasIrregularSpaces() {
2011-05-05 18:02:56 +00:00
return token.source.split('').reduce(function(prev, curr) {
return prev + (curr == ' ' ? 1 : 0);
}, 0) % self.options.tabLength;
}
});
self.lines = self.source.split('<br/>');
self.lineNumbersWidth = self.lines.length.toString().length * 7 + 7;
self.sourceCodeWidth = 80 * 7 + (
self.lines.length > 40 ? Ox.UI.SCROLLBAR_SIZE : 0
);
self.height = 40 * 14 + (
Math.max.apply(null, self.lines.map(function(line) {
return line.length;
})) > 80 ? Ox.UI.SCROLLBAR_SIZE : 0
);
that.css({
width: self.lineNumbersWidth + self.sourceCodeWidth,
height: self.height
});
self.$lineNumbers = new Ox.Element()
.addClass('OxLineNumbers')
.css({
width: self.lineNumbersWidth + 'px',
height: (self.lines.length * 14) + 'px'
})
.html(
Ox.range(self.lines.length).map(function(line) {
return (line + 1) + '&nbsp;';
}).join('<br/>')
)
.appendTo(that);
self.$source = new Ox.Element()
.addClass('OxSourceCode')
.css({
left: self.lineNumbersWidth + 'px',
width: self.sourceCodeWidth + 'px',
height: (self.lines.length * 14) + 'px'
})
.html(self.source)
.appendTo(that);
2011-05-05 18:02:56 +00:00
function encodeToken(source, type) {
var linebreak = '<br/>',
tab = Ox.repeat('&nbsp;', self.options.tabLength);
if (self.options.showLinebreaks) {
if (type == 'linebreak') {
2011-05-05 18:02:56 +00:00
linebreak = '\u21A9' + linebreak;
} else {
2011-05-05 18:02:56 +00:00
linebreak = '<span class="OxLinebreak">\u21A9</span>' + linebreak;
}
}
if (self.options.showTabs) {
tab = '<span class="OxTab">\u2192' + tab.substr(6) + '</span>';
}
2011-05-05 18:02:56 +00:00
source = Ox.encodeHTML(source)
.replace(/ /g, '&nbsp;')
.replace(/\t/g, tab)
.replace(/\n/g, linebreak);
2011-05-05 18:02:56 +00:00
return source;
}
2011-04-29 12:40:51 +00:00
self.setOption = function() {
};
return that;
};