diff --git a/script/directives.js b/script/directives.js
new file mode 100644
index 0000000000..0f159aa7a4
--- /dev/null
+++ b/script/directives.js
@@ -0,0 +1,102 @@
+'use strict';
+
+/**
+ * Markdown
+ * See http://www.heikura.me/#!/angularjs-markdown-directive
+ */
+(function(){
+ var md = function () {
+ marked.setOptions({
+ gfm:true,
+ pedantic:false,
+ sanitize:true
+ // callback for code highlighter
+ // Uncomment this (and htljs.tabReplace below) if we add in highlight.js (http://www.heikura.me/#!/angularjs-markdown-directive)
+// highlight:function (code, lang) {
+// if (lang != undefined)
+// return hljs.highlight(lang, code).value;
+//
+// return hljs.highlightAuto(code).value;
+// }
+ });
+
+ emoji.img_path = 'bower_components/habitrpg-shared/img/emoji/unicode/';
+
+ var toHtml = function (markdown) {
+ if (markdown == undefined)
+ return '';
+
+ markdown = marked(markdown);
+ markdown = emoji.replace_colons(markdown);
+ markdown = emoji.replace_unified(markdown);
+
+ return markdown;
+ };
+
+ // [nickgordon20131123] this hacky override wraps images with a link to the image in a new window, and also adds some classes in case we want to style
+ marked.InlineLexer.prototype.outputLink = function(cap, link) {
+ var escape = function(html, encode) {
+ return html
+ .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ };
+ if (cap[0].charAt(0) !== '!') {
+ return ''
+ + this.output(cap[1])
+ + '';
+ } else {
+ return '
';
+ }
+ }
+
+ //hljs.tabReplace = ' ';
+
+ return {
+ toHtml:toHtml
+ };
+ }();
+
+ habitrpg.directive('markdown', function() {
+ return {
+ restrict: 'E',
+ link: function(scope, element, attrs) {
+ scope.$watch(attrs.ngModel, function(value, oldValue) {
+ var markdown = value;
+ var linktarget = attrs.target || '_self';
+ var html = md.toHtml(markdown);
+ html = html.replace(' href','target="'+linktarget+'" href');
+ element.html(html);
+ });
+ }
+ };
+ });
+})()
\ No newline at end of file