| 1 | (function(angular, $, _) { |
| 2 | angular.module('crmMonaco', CRM.angRequires('crmMonaco')); |
| 3 | |
| 4 | // "crmMonaco" is a basic skeletal directive. |
| 5 | // Example usage: <div crm-monaco ng-model="my.content"></div> |
| 6 | // Example usage: <div crm-monaco="{readOnly: true}" ng-model="my.content"></div> |
| 7 | angular.module('crmMonaco').directive('crmMonaco', function($timeout, $parse) { |
| 8 | return { |
| 9 | restrict: 'AE', |
| 10 | require: ['ngModel', 'crmMonaco'], |
| 11 | template: '<div class="crm-monaco-container"></div>', |
| 12 | controller: function() { |
| 13 | this.editor = null; // Filled in by link(). |
| 14 | }, |
| 15 | link: function($scope, $el, $attr, controllers) { |
| 16 | var ngModel = controllers[0], crmMonaco = controllers[1]; |
| 17 | var heightPct = 0.70; |
| 18 | var editor; |
| 19 | require.config({paths: CRM.crmMonaco.paths}); |
| 20 | require(['vs/editor/editor.main'], function() { |
| 21 | var options = { |
| 22 | readOnly: false, |
| 23 | language: 'html', |
| 24 | // theme: 'vs-dark', |
| 25 | theme: 'vs' |
| 26 | }; |
| 27 | if ($attr.crmMonaco) { |
| 28 | angular.extend(options, $parse($attr.crmMonaco)($scope)); |
| 29 | } |
| 30 | angular.extend(options, { |
| 31 | value: ngModel.$modelValue, |
| 32 | minimap: { |
| 33 | enabled: false |
| 34 | }, |
| 35 | automaticLayout: true, |
| 36 | scrollbar: { |
| 37 | useShadows: false, |
| 38 | verticalHasArrows: true, |
| 39 | horizontalHasArrows: true, |
| 40 | vertical: 'visible', |
| 41 | horizontal: 'visible', |
| 42 | verticalScrollbarSize: 17, |
| 43 | horizontalScrollbarSize: 17, |
| 44 | arrowSize: 30 |
| 45 | } |
| 46 | }); |
| 47 | |
| 48 | heightPct = options.crmHeightPct || heightPct; |
| 49 | delete options.crmHeightPct; |
| 50 | |
| 51 | var editorEl = $el.find('.crm-monaco-container'); |
| 52 | editorEl.css({height: Math.round(heightPct * $(window).height())}); |
| 53 | editor = monaco.editor.create(editorEl[0], options); |
| 54 | |
| 55 | editor.onDidChangeModelContent(_.debounce(function () { |
| 56 | $scope.$apply(function () { |
| 57 | ngModel.$setViewValue(editor.getValue()); |
| 58 | }); |
| 59 | }, 150)); |
| 60 | |
| 61 | ngModel.$render = function() { |
| 62 | if (editor) { |
| 63 | editor.setValue(ngModel.$modelValue); |
| 64 | } |
| 65 | // FIXME: else: retry? |
| 66 | }; |
| 67 | |
| 68 | if ($attr.ngDisabled) { |
| 69 | $scope.$watch($parse($attr.ngDisabled), function(disabled){ |
| 70 | editor.updateOptions({readOnly: disabled}); |
| 71 | }); |
| 72 | } |
| 73 | |
| 74 | // FIXME: This makes vertical scrolling much better, but horizontal is still weird. |
| 75 | var origOverflow; |
| 76 | function bodyScrollSuspend() { |
| 77 | if (origOverflow !== undefined) return; |
| 78 | origOverflow = $('body').css('overflow'); |
| 79 | $('body').css('overflow', 'hidden'); |
| 80 | } |
| 81 | function bodyScrollRestore() { |
| 82 | if (origOverflow === undefined) return; |
| 83 | $('body').css('overflow', origOverflow); |
| 84 | origOverflow = undefined; |
| 85 | } |
| 86 | editorEl.on('mouseenter', bodyScrollSuspend); |
| 87 | editorEl.on('mouseleave', bodyScrollRestore); |
| 88 | editor.onDidFocusEditorWidget(bodyScrollSuspend); |
| 89 | editor.onDidBlurEditorWidget(bodyScrollRestore); |
| 90 | |
| 91 | crmMonaco.editor = editor; |
| 92 | |
| 93 | $scope.$on('$destroy', function () { |
| 94 | bodyScrollRestore(); |
| 95 | if (editor) editor.dispose(); |
| 96 | delete crmMonaco.editor; |
| 97 | }); |
| 98 | }); |
| 99 | } |
| 100 | }; |
| 101 | }); |
| 102 | |
| 103 | angular.module('crmMonaco').directive('crmMonacoInsertRx', function() { |
| 104 | return { |
| 105 | require: 'crmMonaco', |
| 106 | link: function(scope, element, attrs, crmMonaco) { |
| 107 | scope.$on(attrs.crmMonacoInsertRx, function(e, tokenName) { |
| 108 | var editor = crmMonaco.editor; |
| 109 | var id = { major: 1, minor: 1 }; |
| 110 | var op = {identifier: id, range: editor.getSelection(), text: tokenName, forceMoveMarkers: true}; |
| 111 | editor.executeEdits("tokens", [op]); |
| 112 | editor.focus(); |
| 113 | }); |
| 114 | } |
| 115 | }; |
| 116 | }); |
| 117 | |
| 118 | })(angular, CRM.$, CRM._); |