diff --git a/packages/rocketchat-katex/katex.coffee b/packages/rocketchat-katex/katex.coffee
deleted file mode 100644
index 6e7973f94377..000000000000
--- a/packages/rocketchat-katex/katex.coffee
+++ /dev/null
@@ -1,181 +0,0 @@
-###
-# KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
-# https://github.com/Khan/KaTeX
-###
-
-katex = require('katex')
-
-class Katex
- constructor: ->
- @delimiters_map = [
- { opener: '\\[', closer: '\\]', displayMode: true , enabled: () => @parenthesis_syntax_enabled() },
- { opener: '\\(', closer: '\\)', displayMode: false, enabled: () => @parenthesis_syntax_enabled() },
- { opener: '$$' , closer: '$$' , displayMode: true , enabled: () => @dollar_syntax_enabled() },
- { opener: '$' , closer: '$' , displayMode: false, enabled: () => @dollar_syntax_enabled() },
- ]
-
- # Searches for the first opening delimiter in the string from a given position
- find_opening_delimiter: (str, start) -> # Search the string for each opening delimiter
- matches = ({options: o, pos: str.indexOf(o.opener, start)} for o in @delimiters_map when o.enabled())
- positions = (m.pos for m in matches when m.pos >= 0)
-
- # No opening delimiters were found
- if positions.length == 0
- return null
-
- # Take the first delimiter found
- pos = Math.min.apply Math, positions
-
- match_index = (m.pos for m in matches).indexOf(pos)
- match = matches[match_index]
-
- return match
-
- class Boundary
- length: ->
- return @end - @start
-
- extract: (str) ->
- return str.substr @start, @length()
-
- # Returns the outer and inner boundaries of the latex block starting
- # at the given opening delimiter
- get_latex_boundaries: (str, opening_delimiter_match) ->
- inner = new Boundary
- outer = new Boundary
-
- # The closing delimiter matching to the opening one
- closer = opening_delimiter_match.options.closer
-
- outer.start = opening_delimiter_match.pos
- inner.start = opening_delimiter_match.pos + closer.length
-
- # Search for a closer delimiter after the opening one
- closer_index = str.substr(inner.start).indexOf(closer)
- if closer_index < 0
- return null
-
- inner.end = inner.start + closer_index
- outer.end = inner.end + closer.length
-
- return {
- outer: outer
- inner: inner
- }
-
- # Searches for the first latex block in the given string
- find_latex: (str) ->
- start = 0
- while (opening_delimiter_match = @find_opening_delimiter str, start++)?
-
- match = @get_latex_boundaries str, opening_delimiter_match
-
- if match?.inner.extract(str).trim().length
- match.options = opening_delimiter_match.options
- return match
-
- return null
-
- # Breaks a message to what comes before, after and to the content of a
- # matched latex block
- extract_latex: (str, match) ->
- before = str.substr 0, match.outer.start
- after = str.substr match.outer.end
-
- latex = match.inner.extract str
- latex = s.unescapeHTML latex
-
- return { before: before, latex : latex, after : after }
-
- # Takes a latex math string and the desired display mode and renders it
- # to HTML using the KaTeX library
- render_latex: (latex, displayMode) ->
- try
- rendered = katex.renderToString latex , {displayMode: displayMode}
- catch e
- display_mode = if displayMode then "block" else "inline"
- rendered = "
"
- rendered += "#{s.escapeHTML e.message}"
- rendered += "
"
-
- return rendered
-
- # Takes a string and renders all latex blocks inside it
- render: (str, render_func) ->
- result = ''
-
- loop
-
- # Find the first latex block in the string
- match = @find_latex str
-
- unless match?
- result += str
- break
-
- parts = @extract_latex str, match
-
- # Add to the reuslt what comes before the latex block as well as
- # the rendered latex content
- rendered = render_func parts.latex, match.options.displayMode
- result += parts.before + rendered
-
- # Set what comes after the latex block to be examined next
- str = parts.after
-
- return result
-
- # Takes a rocketchat message and renders latex in its content
- render_message: (message) ->
- # Render only if enabled in admin panel
- if @katex_enabled()
- msg = message
-
- if not _.isString message
- if _.trim message.html
- msg = message.html
- else
- return message
-
- if _.isString message
- render_func = (latex, displayMode) =>
- return @render_latex latex, displayMode
- else
- message.tokens ?= []
-
- render_func = (latex, displayMode) =>
- token = "=!=#{Random.id()}=!="
-
- message.tokens.push
- token: token
- text: @render_latex latex, displayMode
-
- return token
-
- msg = @render msg, render_func
-
- if not _.isString message
- message.html = msg
- else
- message = msg
-
- return message
-
- katex_enabled: ->
- return RocketChat.settings.get('Katex_Enabled')
-
- dollar_syntax_enabled: ->
- return RocketChat.settings.get('Katex_Dollar_Syntax')
-
- parenthesis_syntax_enabled: ->
- return RocketChat.settings.get('Katex_Parenthesis_Syntax')
-
-
-RocketChat.katex = new Katex
-
-cb = RocketChat.katex.render_message.bind(RocketChat.katex)
-RocketChat.callbacks.add 'renderMessage', cb, RocketChat.callbacks.priority.HIGH - 1, 'katex'
-
-if Meteor.isClient
- Blaze.registerHelper 'RocketChatKatex', (text) ->
- return RocketChat.katex.render_message text
diff --git a/packages/rocketchat-katex/katex.js b/packages/rocketchat-katex/katex.js
new file mode 100644
index 000000000000..234165def86d
--- /dev/null
+++ b/packages/rocketchat-katex/katex.js
@@ -0,0 +1,255 @@
+/*
+ * KaTeX is a fast, easy-to-use JavaScript library for TeX math rendering on the web.
+ * https://github.com/Khan/KaTeX
+ */
+const katex = require('katex');
+
+class Boundary {
+ constructor() {}
+
+ length() {
+ return this.end - this.start;
+ }
+
+ extract(str) {
+ return str.substr(this.start, this.length());
+ }
+
+}
+
+class Katex {
+ constructor() {
+ this.delimiters_map = [
+ {
+ opener: '\\[',
+ closer: '\\]',
+ displayMode: true,
+ enabled: () => {
+ return this.parenthesis_syntax_enabled();
+ }
+ }, {
+ opener: '\\(',
+ closer: '\\)',
+ displayMode: false,
+ enabled: () => {
+ return this.parenthesis_syntax_enabled();
+ }
+ }, {
+ opener: '$$',
+ closer: '$$',
+ displayMode: true,
+ enabled: () => {
+ return this.dollar_syntax_enabled();
+ }
+ }, {
+ opener: '$',
+ closer: '$',
+ displayMode: false,
+ enabled: () => {
+ return this.dollar_syntax_enabled();
+ }
+ }
+ ];
+ }
+ // Searches for the first opening delimiter in the string from a given position
+
+ find_opening_delimiter(str, start) { // Search the string for each opening delimiter
+ const matches = (() => {
+ const map = this.delimiters_map;
+ const results = [];
+
+ map.forEach((op) => {
+ if (op.enabled()) {
+ results.push({
+ options: op,
+ pos: str.indexOf(op.opener, start)
+ });
+ }
+ });
+ return results;
+ })();
+
+ const positions = (() => {
+ const results = [];
+ matches.forEach((pos) => {
+ if (pos.pos >= 0) {
+ results.push(pos.pos);
+ }
+ });
+ return results;
+ })();
+
+ // No opening delimiters were found
+ if (positions.length === 0) {
+ return null;
+ }
+
+ //Take the first delimiter found
+ const pos = Math.min.apply(Math, positions);
+
+ const match_index = (()=> {
+ const results = [];
+ matches.forEach((m) => {
+ results.push(m.pos);
+ });
+ return results;
+ })().indexOf(pos);
+
+ const match = matches[match_index];
+ return match;
+ }
+
+ // Returns the outer and inner boundaries of the latex block starting
+ // at the given opening delimiter
+ get_latex_boundaries(str, opening_delimiter_match) {
+ const inner = new Boundary;
+ const outer = new Boundary;
+
+ // The closing delimiter matching to the opening one
+ const closer = opening_delimiter_match.options.closer;
+ outer.start = opening_delimiter_match.pos;
+ inner.start = opening_delimiter_match.pos + closer.length;
+
+ // Search for a closer delimiter after the opening one
+ const closer_index = str.substr(inner.start).indexOf(closer);
+ if (closer_index < 0) {
+ return null;
+ }
+ inner.end = inner.start + closer_index;
+ outer.end = inner.end + closer.length;
+ return {
+ outer,
+ inner
+ };
+ }
+
+ // Searches for the first latex block in the given string
+ find_latex(str) {
+ let start = 0;
+ let opening_delimiter_match;
+
+ while ((opening_delimiter_match = this.find_opening_delimiter(str, start++)) != null) {
+ const match = this.get_latex_boundaries(str, opening_delimiter_match);
+ if (match && match.inner.extract(str).trim().length) {
+ match.options = opening_delimiter_match.options;
+ return match;
+ }
+ }
+ return null;
+ }
+
+ // Breaks a message to what comes before, after and to the content of a
+ // matched latex block
+ extract_latex(str, match) {
+ const before = str.substr(0, match.outer.start);
+ const after = str.substr(match.outer.end);
+ let latex = match.inner.extract(str);
+ latex = s.unescapeHTML(latex);
+ return {
+ before,
+ latex,
+ after
+ };
+ }
+
+ // Takes a latex math string and the desired display mode and renders it
+ // to HTML using the KaTeX library
+ render_latex(latex, displayMode) {
+ let rendered;
+ try {
+ rendered = katex.renderToString(latex, {
+ displayMode
+ });
+ } catch (error) {
+ const e = error;
+ const display_mode = displayMode ? 'block' : 'inline';
+ rendered = ``;
+ rendered += `${ s.escapeHTML(e.message) }`;
+ rendered += '
';
+ }
+ return rendered;
+ }
+
+ // Takes a string and renders all latex blocks inside it
+ render(str, render_func) {
+ let result = '';
+ while (this.find_latex(str) != null) {
+ // Find the first latex block in the string
+ const match = this.find_latex(str);
+ const parts = this.extract_latex(str, match);
+
+ // Add to the reuslt what comes before the latex block as well as
+ // the rendered latex content
+ const rendered = render_func(parts.latex, match.options.displayMode);
+ result += parts.before + rendered;
+ // Set what comes after the latex block to be examined next
+ str = parts.after;
+ }
+ return result += str;
+ }
+
+ // Takes a rocketchat message and renders latex in its content
+ render_message(message) {
+ //Render only if enabled in admin panel
+ let render_func;
+ if (this.katex_enabled()) {
+ let msg = message;
+ if (!_.isString(message)) {
+ if (_.trim(message.html)) {
+ msg = message.html;
+ } else {
+ return message;
+ }
+ }
+ if (_.isString(message)) {
+ render_func = (latex, displayMode) => {
+ return this.render_latex(latex, displayMode);
+ };
+ } else {
+ if (message.tokens == null) {
+ message.tokens = [];
+ }
+ render_func = (latex, displayMode) => {
+ const token = `=!=${ Random.id() }=!=`;
+ message.tokens.push({
+ token,
+ text: this.render_latex(latex, displayMode)
+ });
+ return token;
+ };
+ }
+ msg = this.render(msg, render_func);
+ if (!_.isString(message)) {
+ message.html = msg;
+ } else {
+ message = msg;
+ }
+ }
+ return message;
+ }
+
+ katex_enabled() {
+ return RocketChat.settings.get('Katex_Enabled');
+ }
+
+ dollar_syntax_enabled() {
+ return RocketChat.settings.get('Katex_Dollar_Syntax');
+ }
+
+ parenthesis_syntax_enabled() {
+ return RocketChat.settings.get('Katex_Parenthesis_Syntax');
+ }
+
+}
+
+RocketChat.katex = new Katex;
+
+const cb = RocketChat.katex.render_message.bind(RocketChat.katex);
+
+RocketChat.callbacks.add('renderMessage', cb, RocketChat.callbacks.priority.HIGH - 1, 'katex');
+
+if (Meteor.isClient) {
+ Blaze.registerHelper('RocketChatKatex', function(text) {
+ return RocketChat.katex.render_message(text);
+ });
+}
diff --git a/packages/rocketchat-katex/package.js b/packages/rocketchat-katex/package.js
index 033ea7efeeea..de08f7f50f5d 100644
--- a/packages/rocketchat-katex/package.js
+++ b/packages/rocketchat-katex/package.js
@@ -6,15 +6,14 @@ Package.describe({
});
Package.onUse(function(api) {
- api.use('coffeescript');
api.use('ecmascript');
api.use('underscore');
api.use('templating');
api.use('underscorestring:underscore.string');
api.use('rocketchat:lib');
- api.addFiles('settings.coffee', 'server');
- api.addFiles('katex.coffee');
+ api.addFiles('settings.js', 'server');
+ api.addFiles('katex.js');
api.addFiles('client/style.css', 'client');
const katexPath = 'node_modules/katex/dist/';
diff --git a/packages/rocketchat-katex/settings.coffee b/packages/rocketchat-katex/settings.coffee
deleted file mode 100644
index 255aa3dc9c23..000000000000
--- a/packages/rocketchat-katex/settings.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-Meteor.startup ->
- enableQuery = {_id: 'Katex_Enabled', value: true}
- RocketChat.settings.add 'Katex_Enabled', true, {type: 'boolean', group: 'Message', section: 'Katex', public: true, i18n: 'Katex_Enabled_Description'}
-
- RocketChat.settings.add 'Katex_Parenthesis_Syntax', true, {type: 'boolean', group: 'Message', section: 'Katex', public: true, enableQuery, i18nDescription: 'Katex_Parenthesis_Syntax_Description'}
- RocketChat.settings.add 'Katex_Dollar_Syntax', false, {type: 'boolean', group: 'Message', section: 'Katex', public: true, enableQuery, i18nDescription: 'Katex_Dollar_Syntax_Description'}
diff --git a/packages/rocketchat-katex/settings.js b/packages/rocketchat-katex/settings.js
new file mode 100644
index 000000000000..006ef790e64b
--- /dev/null
+++ b/packages/rocketchat-katex/settings.js
@@ -0,0 +1,32 @@
+Meteor.startup(function() {
+ const enableQuery = {
+ _id: 'Katex_Enabled',
+ value: true
+ };
+ RocketChat.settings.add('Katex_Enabled', true, {
+ type: 'boolean',
+ group: 'Message',
+ section: 'Katex',
+ 'public': true,
+ i18n: 'Katex_Enabled_Description'
+ });
+ RocketChat.settings.add('Katex_Parenthesis_Syntax', true, {
+ type: 'boolean',
+ group: 'Message',
+ section: 'Katex',
+ 'public': true,
+ enableQuery,
+ i18nDescription: 'Katex_Parenthesis_Syntax_Description'
+ });
+ return RocketChat.settings.add('Katex_Dollar_Syntax', false, {
+ type: 'boolean',
+ group: 'Message',
+ section: 'Katex',
+ 'public': true,
+ enableQuery,
+ i18nDescription: 'Katex_Dollar_Syntax_Description'
+ });
+});
+
+// ---
+// generated by coffee-script 1.9.2