Skip to content
This repository was archived by the owner on Sep 8, 2020. It is now read-only.

Commit 1e648ed

Browse files
committed
Data binding support added for ace options and JSDoc blocks added.
1 parent b2024c1 commit 1e648ed

File tree

1 file changed

+131
-55
lines changed

1 file changed

+131
-55
lines changed

src/ui-ace.js

Lines changed: 131 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,134 @@
11
'use strict';
22

33
/**
4-
* Binds a ACE Ediitor widget
4+
* Binds a ACE Editor widget
55
*/
66
angular.module('ui.ace', [])
77
.constant('uiAceConfig', {})
88
.directive('uiAce', ['uiAceConfig', function (uiAceConfig) {
9+
910
if (angular.isUndefined(window.ace)) {
1011
throw new Error('ui-ace need ace to work... (o rly?)');
1112
}
13+
14+
/**
15+
* Sets editor options such as the wrapping mode or the syntax checker.
16+
*
17+
* The supported options are:
18+
*
19+
* <ul>
20+
* <li>showGutter</li>
21+
* <li>useWrapMode</li>
22+
* <li>onLoad</li>
23+
* <li>theme</li>
24+
* <li>mode</li>
25+
* </ul>
26+
*
27+
* @param acee
28+
* @param session ACE editor session
29+
* @param {object} opts Options to be set
30+
*/
31+
var setOptions = function(acee, session, opts) {
32+
33+
// Boolean options
34+
if (angular.isDefined(opts.showGutter)) {
35+
acee.renderer.setShowGutter(opts.showGutter);
36+
}
37+
if (angular.isDefined(opts.useWrapMode)) {
38+
session.setUseWrapMode(opts.useWrapMode);
39+
}
40+
41+
// onLoad callback
42+
if (angular.isFunction(opts.onLoad)) {
43+
opts.onLoad(acee);
44+
}
45+
46+
// Basic options
47+
if (angular.isString(opts.theme)) {
48+
acee.setTheme('ace/theme/' + opts.theme);
49+
}
50+
if (angular.isString(opts.mode)) {
51+
session.setMode('ace/mode/' + opts.mode);
52+
}
53+
}
54+
1255
return {
1356
restrict: 'EA',
1457
require: '?ngModel',
1558
link: function (scope, elm, attrs, ngModel) {
16-
var options, opts, acee, session, onChange;
17-
18-
options = uiAceConfig.ace || {};
19-
opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
20-
21-
acee = window.ace.edit(elm[0]);
22-
session = acee.getSession();
23-
24-
onChange = function (callback) {
25-
return function (e) {
26-
var newValue = session.getValue();
27-
if (newValue !== scope.$eval(attrs.value) && !scope.$$phase && !scope.$root.$$phase) {
28-
if (angular.isDefined(ngModel)) {
29-
scope.$apply(function () {
30-
ngModel.$setViewValue(newValue);
31-
});
32-
}
3359

34-
/**
35-
* Call the user onChange function.
36-
*/
37-
if (angular.isDefined(callback)) {
38-
scope.$apply(function () {
39-
if (angular.isFunction(callback)) {
40-
callback(e, acee);
41-
}
42-
else {
43-
throw new Error('ui-ace use a function as callback.');
44-
}
45-
});
46-
}
47-
}
48-
};
49-
};
60+
/**
61+
* Corresponds the uiAceConfig ACE configuration.
62+
* @type object
63+
*/
64+
var options = uiAceConfig.ace || {};
5065

66+
/**
67+
* uiAceConfig merged with user options via json in attribute or data binding
68+
* @type object
69+
*/
70+
var opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
5171

52-
// Boolean options
53-
if (angular.isDefined(opts.showGutter)) {
54-
acee.renderer.setShowGutter(opts.showGutter);
55-
}
56-
if (angular.isDefined(opts.useWrapMode)) {
57-
session.setUseWrapMode(opts.useWrapMode);
58-
}
72+
/**
73+
* ACE editor
74+
* @type object
75+
*/
76+
var acee = window.ace.edit(elm[0]);
5977

60-
// onLoad callback
61-
if (angular.isFunction(opts.onLoad)) {
62-
opts.onLoad(acee);
63-
}
78+
/**
79+
* ACE editor session.
80+
* @type object
81+
* @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
82+
*/
83+
var session = acee.getSession();
6484

65-
// Basic options
66-
if (angular.isString(opts.theme)) {
67-
acee.setTheme('ace/theme/' + opts.theme);
68-
}
69-
if (angular.isString(opts.mode)) {
70-
session.setMode('ace/mode/' + opts.mode);
71-
}
85+
/**
86+
* Reference to a change listener created by the listener factory.
87+
* @function
88+
* @see listenerFactory.onChange
89+
*/
90+
var onChangeListener;
91+
92+
/**
93+
* Listener factory. Until now only change listeners can be created.
94+
* @type object
95+
*/
96+
var listenerFactory = {
97+
/**
98+
* Creates a change listener which propagates the change event
99+
* to the callback from the user option onChange. It might be
100+
* exchanged during runtime, if this happens the old listener
101+
* will be unbound.
102+
*
103+
* @param callback callback function taken from the
104+
* @see onChangeListener
105+
*/
106+
onChange: function (callback) {
107+
return function (e) {
108+
var newValue = session.getValue();
109+
if (newValue !== scope.$eval(attrs.value) && !scope.$$phase && !scope.$root.$$phase) {
110+
if (angular.isDefined(ngModel)) {
111+
scope.$apply(function () {
112+
ngModel.$setViewValue(newValue);
113+
});
114+
}
115+
116+
/**
117+
* Call the user onChange function.
118+
*/
119+
if (angular.isDefined(callback)) {
120+
scope.$apply(function () {
121+
if (angular.isFunction(callback)) {
122+
callback(e, acee);
123+
} else {
124+
throw new Error('ui-ace use a function as callback.');
125+
}
126+
});
127+
}
128+
}
129+
};
130+
}
131+
};
72132

73133
attrs.$observe('readonly', function (value) {
74134
acee.setReadOnly(value === 'true');
@@ -91,20 +151,36 @@ angular.module('ui.ace', [])
91151
};
92152
}
93153

154+
// Listen for option updates
155+
scope.$watch( attrs.uiAce, function() {
156+
opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
157+
158+
// unbind old listener
159+
session.removeListener('change', onChangeListener);
160+
161+
// bind new listener
162+
onChangeListener = listenerFactory.onChange(opts.onChange);
163+
session.on('change', onChangeListener);
164+
165+
setOptions(acee, session, opts);
166+
}, /* deep watch */ true );
167+
94168
// EVENTS
95-
session.on('change', onChange(opts.onChange));
169+
onChangeListener = listenerFactory.onChange(opts.onChange);
170+
session.on('change', onChangeListener);
96171

97-
elm.on('$destroy', function() {
172+
elm.on('$destroy', function () {
98173
acee.session.$stopWorker();
99174
acee.destroy();
100175
});
101-
176+
102177
scope.$watch(function() {
103178
return [elm[0].offsetWidth, elm[0].offsetHeight];
104179
}, function() {
105180
acee.resize();
106181
acee.renderer.updateFull();
107182
}, true);
183+
108184
}
109185
};
110186
}]);

0 commit comments

Comments
 (0)