149 lines
5.4 KiB
JavaScript
149 lines
5.4 KiB
JavaScript
|
/*
|
||
|
* UI.Codemirror directive
|
||
|
* https://github.com/angular-ui/ui-codemirror
|
||
|
*
|
||
|
* This directive allows you to add CodeMirror to your textarea elements.
|
||
|
*
|
||
|
* The MIT License
|
||
|
*
|
||
|
* Copyright (c) 2012 the AngularUI Team, http://angular-ui.github.com
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
* of this software and associated documentation files (the "Software"), to deal
|
||
|
* in the Software without restriction, including without limitation the rights
|
||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
* copies of the Software, and to permit persons to whom the Software is
|
||
|
* furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
* THE SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
/**
|
||
|
* Binds a CodeMirror widget to a <textarea> element.
|
||
|
*/
|
||
|
angular.module('ui.codemirror', [])
|
||
|
.constant('uiCodemirrorConfig', {})
|
||
|
.directive('uiCodemirror', ['uiCodemirrorConfig', function (uiCodemirrorConfig) {
|
||
|
|
||
|
return {
|
||
|
restrict: 'EA',
|
||
|
require: '?ngModel',
|
||
|
priority: 1,
|
||
|
compile: function compile(tElement) {
|
||
|
|
||
|
// Require CodeMirror
|
||
|
if (angular.isUndefined(window.CodeMirror)) {
|
||
|
throw new Error('ui-codemirror need CodeMirror to work... (o rly?)');
|
||
|
}
|
||
|
|
||
|
// Create a codemirror instance with
|
||
|
// - the function that will to place the editor into the document.
|
||
|
// - the initial content of the editor.
|
||
|
// see http://codemirror.net/doc/manual.html#api_constructor
|
||
|
var value = tElement.text();
|
||
|
var codeMirror = new window.CodeMirror(function (cm_el) {
|
||
|
|
||
|
angular.forEach(tElement.prop('attributes'), function (a) {
|
||
|
if (a.name === 'ui-codemirror') {
|
||
|
cm_el.setAttribute('ui-codemirror-opts', a.textContent);
|
||
|
} else {
|
||
|
cm_el.setAttribute(a.name, a.textContent);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// FIX replaceWith throw not parent Error !
|
||
|
if (tElement.parent().length <= 0) {
|
||
|
tElement.wrap('<div>');
|
||
|
}
|
||
|
|
||
|
tElement.replaceWith(cm_el);
|
||
|
}, {value: value});
|
||
|
|
||
|
return function postLink(scope, iElement, iAttrs, ngModel) {
|
||
|
|
||
|
var options, opts;
|
||
|
|
||
|
options = uiCodemirrorConfig.codemirror || {};
|
||
|
opts = angular.extend({}, options, scope.$eval(iAttrs.uiCodemirror), scope.$eval(iAttrs.uiCodemirrorOpts));
|
||
|
|
||
|
function updateOptions(newValues) {
|
||
|
for (var key in newValues) {
|
||
|
if (newValues.hasOwnProperty(key)) {
|
||
|
codeMirror.setOption(key, newValues[key]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
updateOptions(opts);
|
||
|
|
||
|
if (angular.isDefined(scope.$eval(iAttrs.uiCodemirror))) {
|
||
|
scope.$watch(iAttrs.uiCodemirror, updateOptions, true);
|
||
|
}
|
||
|
// Specialize change event
|
||
|
codeMirror.on('change', function (instance) {
|
||
|
var newValue = instance.getValue();
|
||
|
if (ngModel && newValue !== ngModel.$viewValue) {
|
||
|
ngModel.$setViewValue(newValue);
|
||
|
}
|
||
|
if (!scope.$$phase) {
|
||
|
scope.$apply();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
|
||
|
if (ngModel) {
|
||
|
// 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 () {
|
||
|
//Code mirror expects a string so make sure it gets one
|
||
|
//Although the formatter have already done this, it can be possible that another formatter returns undefined (for example the required directive)
|
||
|
var safeViewValue = ngModel.$viewValue || '';
|
||
|
codeMirror.setValue(safeViewValue);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
|
||
|
// Watch ui-refresh and refresh the directive
|
||
|
if (iAttrs.uiRefresh) {
|
||
|
scope.$watch(iAttrs.uiRefresh, function (newVal, oldVal) {
|
||
|
// Skip the initial watch firing
|
||
|
if (newVal !== oldVal) {
|
||
|
codeMirror.refresh();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// onLoad callback
|
||
|
if (angular.isFunction(opts.onLoad)) {
|
||
|
opts.onLoad(codeMirror);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
}]);
|