├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── src └── index.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Kyle J. Kemp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ng2-ace 2 | A basic ace editor directive for angular 2. 3 | 4 | # Install 5 | `npm i -s ng2-ace` 6 | 7 | # Sample Usage 8 | 9 | ```js 10 | import { Component } from 'angular2/core'; 11 | 12 | import { AceEditorDirective } from 'ng2-ace'; 13 | 14 | import 'brace/theme/clouds'; 15 | import 'brace/mode/sql'; 16 | 17 | @Component({ 18 | directives: [AceEditorDirective], 19 | template: ` 20 |
28 | ` 29 | }) 30 | export class MyComponent { 31 | constructor() { 32 | this.text = 'test'; 33 | this.options = { printMargin: false }; 34 | this.onChange = (data) => { 35 | console.log(data); 36 | } 37 | } 38 | } 39 | ``` 40 | Important pieces to note in the HTML template: `[ace-editor]` attribute, `[text]`, `[theme]`, `[mode]`, `[readOnly]`, `[options]` inputs, `(textChanged)` output. As per Ace, you must also make it a `display: block;` and give it a width and height. 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-ace", 3 | "version": "0.0.15", 4 | "description": "An ace editor directive for angular2.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/seiyria/ng2-ace.git" 12 | }, 13 | "keywords": [ 14 | "ng2", 15 | "angular2", 16 | "ace", 17 | "ace", 18 | "editor", 19 | "ng2-ace", 20 | "angular2-ace" 21 | ], 22 | "author": "Kyle Kemp ", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/seiyria/ng2-ace/issues" 26 | }, 27 | "scripts": { 28 | "compile": "babel src/index.js -o index.js --plugins transform-decorators-legacy,transform-class-properties --presets es2015" 29 | }, 30 | "homepage": "https://github.com/seiyria/ng2-ace#readme", 31 | "dependencies": { 32 | "brace": "^0.8.0" 33 | }, 34 | "peerDependencies": { 35 | "@angular/core": "^2.0.0-rc.4" 36 | }, 37 | "devDependencies": { 38 | "babel-plugin-transform-class-properties": "^6.9.0", 39 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 40 | "babel-preset-es2015": "^6.9.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { Directive, ElementRef, EventEmitter } from '@angular/core'; 3 | import ace from 'brace'; 4 | 5 | @Directive({ 6 | selector: '[ace-editor]', 7 | inputs: ['text', 'mode', 'theme', 'readOnly', 'options'], 8 | outputs: ['textChanged', 'editorRef'] 9 | }) 10 | export class AceEditorDirective { 11 | static get parameters() { 12 | return [[ElementRef]]; 13 | } 14 | 15 | set options(value) { 16 | this.editor.setOptions(value || {}); 17 | } 18 | 19 | set readOnly(value) { 20 | this._readOnly = value; 21 | this.editor.setReadOnly(value); 22 | } 23 | 24 | set theme(value) { 25 | this._theme = value; 26 | this.editor.setTheme(`ace/theme/${value}`); 27 | } 28 | 29 | set mode(value) { 30 | this._mode = value; 31 | this.editor.getSession().setMode(`ace/mode/${value}`); 32 | } 33 | 34 | set text(value) { 35 | if(value === this.oldVal) return; 36 | this.editor.setValue(value); 37 | this.editor.clearSelection(); 38 | this.editor.focus(); 39 | } 40 | 41 | constructor(elementRef) { 42 | this.textChanged = new EventEmitter(); 43 | this.editorRef = new EventEmitter(); 44 | 45 | const el = elementRef.nativeElement; 46 | el.classList.add('editor'); 47 | 48 | this.editor = ace.edit(el); 49 | 50 | setTimeout(() => { 51 | this.editorRef.next(this.editor); 52 | }); 53 | 54 | this.editor.on('change', () => { 55 | const newVal = this.editor.getValue(); 56 | if(newVal === this.oldVal) return; 57 | if(typeof this.oldVal !== 'undefined') { 58 | this.textChanged.next(newVal); 59 | } 60 | this.oldVal = newVal; 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.AceEditorDirective = undefined; 7 | 8 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 9 | 10 | var _dec, _class; 11 | 12 | var _core = require('@angular/core'); 13 | 14 | var _brace = require('brace'); 15 | 16 | var _brace2 = _interopRequireDefault(_brace); 17 | 18 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 19 | 20 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 21 | 22 | var AceEditorDirective = exports.AceEditorDirective = (_dec = (0, _core.Directive)({ 23 | selector: '[ace-editor]', 24 | inputs: ['text', 'mode', 'theme', 'readOnly', 'options'], 25 | outputs: ['textChanged', 'editorRef'] 26 | }), _dec(_class = function () { 27 | _createClass(AceEditorDirective, [{ 28 | key: 'options', 29 | set: function set(value) { 30 | this.editor.setOptions(value || {}); 31 | } 32 | }, { 33 | key: 'readOnly', 34 | set: function set(value) { 35 | this._readOnly = value; 36 | this.editor.setReadOnly(value); 37 | } 38 | }, { 39 | key: 'theme', 40 | set: function set(value) { 41 | this._theme = value; 42 | this.editor.setTheme('ace/theme/' + value); 43 | } 44 | }, { 45 | key: 'mode', 46 | set: function set(value) { 47 | this._mode = value; 48 | this.editor.getSession().setMode('ace/mode/' + value); 49 | } 50 | }, { 51 | key: 'text', 52 | set: function set(value) { 53 | if (value === this.oldVal) return; 54 | this.editor.setValue(value); 55 | this.editor.clearSelection(); 56 | this.editor.focus(); 57 | } 58 | }], [{ 59 | key: 'parameters', 60 | get: function get() { 61 | return [[_core.ElementRef]]; 62 | } 63 | }]); 64 | 65 | function AceEditorDirective(elementRef) { 66 | var _this = this; 67 | 68 | _classCallCheck(this, AceEditorDirective); 69 | 70 | this.textChanged = new _core.EventEmitter(); 71 | this.editorRef = new _core.EventEmitter(); 72 | 73 | var el = elementRef.nativeElement; 74 | el.classList.add('editor'); 75 | 76 | this.editor = _brace2.default.edit(el); 77 | 78 | setTimeout(function () { 79 | _this.editorRef.next(_this.editor); 80 | }); 81 | 82 | this.editor.on('change', function () { 83 | var newVal = _this.editor.getValue(); 84 | if (newVal === _this.oldVal) return; 85 | if (typeof _this.oldVal !== 'undefined') { 86 | _this.textChanged.next(newVal); 87 | } 88 | _this.oldVal = newVal; 89 | }); 90 | } 91 | 92 | return AceEditorDirective; 93 | }()) || _class); 94 | --------------------------------------------------------------------------------