summaryrefslogtreecommitdiffstats
path: root/js/vendor/angular-ui/modules/directives/codemirror
diff options
context:
space:
mode:
Diffstat (limited to 'js/vendor/angular-ui/modules/directives/codemirror')
-rw-r--r--js/vendor/angular-ui/modules/directives/codemirror/codemirror.js77
-rw-r--r--js/vendor/angular-ui/modules/directives/codemirror/dependencies.json8
-rw-r--r--js/vendor/angular-ui/modules/directives/codemirror/test/codemirrorSpec.js160
3 files changed, 245 insertions, 0 deletions
diff --git a/js/vendor/angular-ui/modules/directives/codemirror/codemirror.js b/js/vendor/angular-ui/modules/directives/codemirror/codemirror.js
new file mode 100644
index 000000000..403c1cc48
--- /dev/null
+++ b/js/vendor/angular-ui/modules/directives/codemirror/codemirror.js
@@ -0,0 +1,77 @@
+/*global angular, CodeMirror, Error*/
+/**
+ * Binds a CodeMirror widget to a <textarea> element.
+ */
+angular.module('ui.directives').directive('uiCodemirror', ['ui.config', '$timeout', function (uiConfig, $timeout) {
+ 'use strict';
+
+ var events = ["cursorActivity", "viewportChange", "gutterClick", "focus", "blur", "scroll", "update"];
+ return {
+ restrict:'A',
+ require:'ngModel',
+ link:function (scope, elm, attrs, ngModel) {
+ var options, opts, onChange, deferCodeMirror, codeMirror;
+
+ if (elm[0].type !== 'textarea') {
+ throw new Error('uiCodemirror3 can only be applied to a textarea element');
+ }
+
+ options = uiConfig.codemirror || {};
+ opts = angular.extend({}, options, scope.$eval(attrs.uiCodemirror));
+
+ onChange = function (aEvent) {
+ return function (instance, changeObj) {
+ var newValue = instance.getValue();
+ if (newValue !== ngModel.$viewValue) {
+ ngModel.$setViewValue(newValue);
+ scope.$apply();
+ }
+ if (typeof aEvent === "function")
+ aEvent(instance, changeObj);
+ };
+ };
+
+ deferCodeMirror = function () {
+ codeMirror = CodeMirror.fromTextArea(elm[0], opts);
+ codeMirror.on("change", onChange(opts.onChange));
+
+ for (var i = 0, n = events.length, aEvent; i < n; ++i) {
+ aEvent = opts["on" + events[i].charAt(0).toUpperCase() + events[i].slice(1)];
+ if (aEvent === void 0) continue;
+ if (typeof aEvent !== "function") continue;
+ codeMirror.on(events[i], aEvent);
+ }
+
+ // CodeMirror expects a string, so make sure it gets one.
+ // This does not change the model.
+ ngModel.$formatters.push(function (value) {
+ if (angular.isUndefined(value) || value === null) {
+ return '';
+ }
+ else if (angular.isObject(value) || angular.isArray(value)) {
+ throw new Error('ui-codemirror cannot use an object or an array as a model');
+ }
+ return value;
+ });
+
+ // Override the ngModelController $render method, which is what gets called when the model is updated.
+ // This takes care of the synchronizing the codeMirror element with the underlying model, in the case that it is changed by something else.
+ ngModel.$render = function () {
+ codeMirror.setValue(ngModel.$viewValue);
+ };
+
+ // Watch ui-refresh and refresh the directive
+ if (attrs.uiRefresh) {
+ scope.$watch(attrs.uiRefresh, function(newVal, oldVal){
+ // Skip the initial watch firing
+ if (newVal !== oldVal)
+ $timeout(codeMirror.refresh);
+ });
+ }
+ };
+
+ $timeout(deferCodeMirror);
+
+ }
+ };
+}]);
diff --git a/js/vendor/angular-ui/modules/directives/codemirror/dependencies.json b/js/vendor/angular-ui/modules/directives/codemirror/dependencies.json
new file mode 100644
index 000000000..30dd1ff35
--- /dev/null
+++ b/js/vendor/angular-ui/modules/directives/codemirror/dependencies.json
@@ -0,0 +1,8 @@
+{
+ "core": [ "jquery" ],
+ "internal": [],
+ "external": [
+ "http://codemirror.net/lib/codemirror.js",
+ "http://codemirror.net/lib/codemirror.css",
+ ]
+} \ No newline at end of file
diff --git a/js/vendor/angular-ui/modules/directives/codemirror/test/codemirrorSpec.js b/js/vendor/angular-ui/modules/directives/codemirror/test/codemirrorSpec.js
new file mode 100644
index 000000000..5e6bf3d37
--- /dev/null
+++ b/js/vendor/angular-ui/modules/directives/codemirror/test/codemirrorSpec.js
@@ -0,0 +1,160 @@
+/*global beforeEach, afterEach, describe, it, inject, expect, module, spyOn, CodeMirror, angular, $*/
+/**
+ * TODO Test all the CodeMirror events : cursorActivity viewportChange gutterClick focus blur scroll update.
+ * with <textarea ui-codemirror="{onChange: doChange ,onCursorActivity: doSomething}" ng-model="foo">
+ *
+ */
+describe('uiCodemirror', function () {
+ 'use strict';
+
+ // declare these up here to be global to all tests
+ var scope, $compile, $timeout, uiConfig = angular.module('ui.config');
+
+ beforeEach(module('ui.directives'));
+ beforeEach(function () {
+ uiConfig.value('ui.config', {codemirror: {bar: 'baz'}});
+ });
+
+ // inject in angular constructs. Injector knows about leading/trailing underscores and does the right thing
+ // otherwise, you would need to inject these into each test
+ beforeEach(inject(function (_$rootScope_, _$compile_, _$timeout_) {
+ scope = _$rootScope_.$new();
+ $compile = _$compile_;
+ $timeout = _$timeout_;
+ }));
+
+ afterEach(function () {
+ uiConfig.value('ui.config', {}); // cleanup
+ });
+
+ describe('compiling this directive', function () {
+ it('should throw an error if used against a non-textarea', function () {
+ function compile() {
+ $compile('<div ui-codemirror ng-model="foo"></div>')(scope);
+ }
+
+ expect(compile).toThrow();
+ });
+
+ it('should not throw an error when used against a textarea', function () {
+ function compile() {
+ $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ }
+
+ expect(compile).not.toThrow();
+ });
+
+ it('should throw an error when no ngModel attribute defined', function () {
+ function compile() {
+ $compile('<textarea ui-codemirror></textarea>')(scope);
+ }
+
+ expect(compile).toThrow();
+ });
+
+ it('should watch the uiCodemirror attribute', function () {
+ spyOn(scope, '$watch');
+ $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ $timeout.flush();
+ expect(scope.$watch).toHaveBeenCalled();
+ });
+
+ });
+
+ describe('while spying on the CodeMirror instance', function () {
+
+ var codemirror;
+
+ beforeEach(function () {
+ var fromTextArea = CodeMirror.fromTextArea;
+ spyOn(CodeMirror, 'fromTextArea').andCallFake(function () {
+ codemirror = fromTextArea.apply(this, arguments);
+ return codemirror;
+ });
+ });
+
+ describe('verify the directive options', function () {
+ it('should include the passed options', function () {
+ $compile('<textarea ui-codemirror="{oof: \'baar\'}" ng-model="foo"></textarea>')(scope);
+ $timeout.flush();
+ expect(CodeMirror.fromTextArea.mostRecentCall.args[1].oof).toEqual("baar");
+ });
+
+ it('should include the default options', function () {
+ $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ $timeout.flush();
+ expect(CodeMirror.fromTextArea.mostRecentCall.args[1].bar).toEqual('baz');
+ });
+ });
+
+ describe('when uiRefresh is added', function () {
+ it('should trigger the CodeMirror.refresh() method', function () {
+ $compile('<textarea ui-codemirror ng-model="foo" ui-refresh="bar"></textarea>')(scope);
+ $timeout.flush();
+ spyOn(codemirror, 'refresh');
+ scope.$apply('bar = true');
+ $timeout.flush();
+ expect(codemirror.refresh).toHaveBeenCalled();
+ });
+ });
+
+
+ describe('when the IDE changes', function () {
+ it('should update the model', function () {
+ $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ scope.$apply("foo = 'bar'");
+ $timeout.flush();
+ var value = 'baz';
+ codemirror.setValue(value);
+ expect(scope.foo).toBe(value);
+ });
+ });
+
+ describe('when the model changes', function () {
+ it('should update the IDE', function () {
+ var element = $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ scope.foo = 'bar';
+ scope.$apply();
+ $timeout.flush();
+ expect(codemirror.getValue()).toBe(scope.foo);
+ });
+ });
+
+ describe('when the model is undefined/null', function () {
+ it('should update the IDE with an empty string', function () {
+ var element = $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ scope.$apply();
+ $timeout.flush();
+ expect(scope.foo).toBe(undefined);
+ expect(codemirror.getValue()).toBe('');
+ scope.$apply('foo = "bar"');
+ expect(scope.foo).toBe('bar');
+ expect(codemirror.getValue()).toBe('bar');
+ scope.$apply('foo = null');
+ expect(scope.foo).toBe(null);
+ expect(codemirror.getValue()).toBe('');
+ });
+ });
+ });
+
+ describe('when the model is an object or an array', function () {
+ it('should throw an error', function () {
+ function compileWithObject() {
+ $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ $timeout.flush();
+ scope.foo = {};
+ scope.$apply();
+ }
+
+ function compileWithArray() {
+ $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
+ $timeout.flush();
+ scope.foo = [];
+ scope.$apply();
+ }
+
+ expect(compileWithObject).toThrow();
+ expect(compileWithArray).toThrow();
+ });
+ });
+}); \ No newline at end of file