+ // Update the data models and rendered output
+ function update(instance) {
+ let content = instance.getValue();
+ element.val(content);
+ $timeout(() => {
+ scope.mdModel = content;
+ scope.mdChange(md.render(content));
+ });
+ }
+ update(cm);
+
+ // Listen to commands from parent scope
+ scope.$on('md-insert-link', showLinkSelector);
+ scope.$on('md-insert-image', showImageManager);
+ scope.$on('markdown-update', (event, value) => {
+ cm.setValue(value);
+ element.val(value);
+ scope.mdModel = value;
+ scope.mdChange(md.render(value));
+ });
+
+ }
+ }
+ }]);
+
+ /**
+ * Markdown Editor
+ * Handles all functionality of the markdown editor.
+ */
+ ngApp.directive('markdownEditor', ['$timeout', '$rootScope', function ($timeout, $rootScope) {
+ return {
+ restrict: 'A',
+ link: function (scope, element, attrs) {
+
+ // Editor Elements
+ const $display = element.find('.markdown-display').first();
+ const $insertImage = element.find('button[data-action="insertImage"]');
+ const $insertEntityLink = element.find('button[data-action="insertEntityLink"]');
+
+ // Prevent markdown display link click redirect
+ $display.on('click', 'a', function(event) {
+ event.preventDefault();
+ window.open(this.getAttribute('href'));
+ });
+
+ // Editor UI Actions
+ $insertEntityLink.click(e => {scope.$broadcast('md-insert-link');});
+ $insertImage.click(e => {scope.$broadcast('md-insert-image');});
+
+ // Handle scroll sync event from editor scroll
+ $rootScope.$on('markdown-scroll', (event, lineCount) => {
+ let elems = $display[0].children[0].children;
+ if (elems.length > lineCount) {
+ let topElem = (lineCount === -1) ? elems[elems.length-1] : elems[lineCount];
+ $display.animate({
+ scrollTop: topElem.offsetTop
+ }, {queue: false, duration: 200, easing: 'linear'});
+ }
+ });