From 6e160cb6f12b11365e8480509332951ea43d7e5a Mon Sep 17 00:00:00 2001 From: ciel Date: Fri, 12 Sep 2014 13:10:13 -0500 Subject: [PATCH] feat(directive): require and advanced options add "require" array for specifying ace.require loads, and add "advanced" object in the directive options for specifying unlisted ace options. This is done to try and make customizing the editor more robust from the directive alone, and possibly eliminate the need for controller code related to the editor. --- README.md | 22 +++++++++++++ src/ui-ace.js | 17 +++++++++- test/ace.spec.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 121 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0e5ca19..2e258fe 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,28 @@ myAppModule.controller('MyController', [ '$scope', function($scope) { To handle other options you'll have to use a direct access to the Ace created instance (see [below](#ace-instance-direct-access)). +## Advanced Options + +You can specify advanced options and even `require` options in the directive, as well. For this example, you +will have to include the `ext-language_tools.js` file from the ace source code. + +This will copy the UI.Ace files into a `bower_components` folder, along with its dependencies. Load the script files in your application: + +```html + +``` + +```html +
+``` + ### Working with ng-model The ui-ace directive plays nicely with ng-model. diff --git a/src/ui-ace.js b/src/ui-ace.js index 222953b..3fa3a3a 100644 --- a/src/ui-ace.js +++ b/src/ui-ace.js @@ -29,7 +29,12 @@ angular.module('ui.ace', []) * @param {object} opts Options to be set */ var setOptions = function(acee, session, opts) { - + // ace requires loading + if (angular.isDefined(opts.require)) { + opts.require.forEach(function (n) { + window.ace.require(n); + }); + } // Boolean options if (angular.isDefined(opts.showGutter)) { acee.renderer.setShowGutter(opts.showGutter); @@ -84,6 +89,16 @@ angular.module('ui.ace', []) session.setOption('firstLineNumber', opts.firstLineNumber()); } } + + // advanced options + if (angular.isDefined(opts.advanced)) { + for (var key in opts.advanced) { + // create a javascript object with the key and value + var obj = { name: key, value: opts.advanced[key] }; + // try to assign the option to the ace editor + acee.setOption(obj.name, obj.value); + } + } }; return { diff --git a/test/ace.spec.js b/test/ace.spec.js index 373413e..70c7d16 100644 --- a/test/ace.spec.js +++ b/test/ace.spec.js @@ -8,7 +8,6 @@ describe('uiAce', function () { beforeEach(inject(function (uiAceConfig) { uiConfig = uiAceConfig; uiConfig.ace = {showGutter: false}; - })); // inject in angular constructs. Injector knows about leading/trailing underscores and does the right thing @@ -22,6 +21,89 @@ describe('uiAce', function () { uiConfig = {}; }); + describe('behavior', function () { + var _ace; + + beforeEach(function () { + _ace = window.ace; + spyOn(window.ace, 'require'); + }); + it('should not call window.ace.require if there is no "require" option', function () { + $compile('
')(scope); + expect(_ace.require).not.toHaveBeenCalled(); + }); + }); + + describe('behavior', function () { + var _ace; + + beforeEach(function () { + _ace = window.ace; + spyOn(window.ace, 'require'); + }); + it('should call "window.ace.require" for each option in "require"', function () { + $compile('
')(scope); + expect(_ace.require).toHaveBeenCalled(); + expect(_ace.require.callCount).toEqual(2); + }); + }); + + describe('behavior', function () { + var _ace; + + beforeEach(function () { + var aceEditFunction = window.ace.edit; + spyOn(window.ace, 'edit').andCallFake(function () { + _ace = aceEditFunction.apply(this, arguments); + return _ace; + }); + }); + it('should not call "setOption" if no "advanced" options are given.', function () { + $compile('
')(scope); + var session = _ace.getSession(); + spyOn(session, 'setOption'); + expect(session.setOption).not.toHaveBeenCalled(); + }); + }); + + describe('behavior', function () { + var _ace; + + beforeEach(function () { + var aceEditFunction = window.ace.edit; + spyOn(window.ace, 'edit').andCallFake(function () { + _ace = aceEditFunction.apply(this, arguments); + return _ace; + }); + }); + it('Given advanced option is null if not defined.', function () { + $compile('
')(scope); + var session = _ace.getSession(); + spyOn(session, 'getOption'); + expect(session.getOption).toBeDefined(); + expect(session.getOption('enableSnippets')).not.toBeDefined(); + }); + }); + + describe('behavior', function () { + var _ace; + + beforeEach(function () { + var aceEditFunction = window.ace.edit; + spyOn(window.ace, 'edit').andCallFake(function () { + _ace = aceEditFunction.apply(this, arguments); + return _ace; + }); + }); + it('given advanced options are properly defined.', function () { + $compile('
')(scope); + var session = _ace.getSession(); + spyOn(session, 'getOption'); + expect(session.getOption).toBeDefined(); + expect(session.getOption('enableSnippets')).not.toBe(null); + }); + }); + describe('behavior', function () { it('should not throw an error when window.ace is defined', function () { @@ -38,7 +120,6 @@ describe('uiAce', function () { $compile('
')(scope); expect(scope.$watch).toHaveBeenCalled(); }); - }); describe('instance', function () {