Skip to content
This repository was archived by the owner on May 25, 2019. It is now read-only.

Better webpack minimisation and CommonJs support. #147

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ bower_components/
node_modules/
out/
dist/
.idea/
258 changes: 141 additions & 117 deletions src/ui-codemirror.js
Original file line number Diff line number Diff line change
@@ -1,150 +1,174 @@
/*global module */
'use strict';

/**
* Binds a CodeMirror widget to a <textarea> element.
*/
angular.module('ui.codemirror', [])
.constant('uiCodemirrorConfig', {})
.directive('uiCodemirror', uiCodemirrorDirective);

/**
* @ngInject
*/
function uiCodemirrorDirective($timeout, uiCodemirrorConfig) {

return {
restrict: 'EA',
require: '?ngModel',
compile: function compile() {

// Require CodeMirror
if (angular.isUndefined(window.CodeMirror)) {
throw new Error('ui-codemirror needs CodeMirror to work... (o rly?)');
(function(factory) {
var moduleName = 'ui.codemirror';
if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = moduleName;
factory(moduleName);
} else {
factory(moduleName);
}
}(function(moduleName) {

/**
* Binds a CodeMirror widget to a <textarea> element.
*/
angular.module(moduleName, [])
.constant('uiCodemirrorConfig', {})
.directive('uiCodemirror', ['$timeout', 'uiCodemirrorConfig', uiCodemirrorDirective]);

/**
* @ngInject
*/
function uiCodemirrorDirective($timeout, uiCodemirrorConfig) {

return {
restrict: 'EA',
require: '?ngModel',
compile: function compile() {

// Require CodeMirror
if (angular.isUndefined(window.CodeMirror)) {
throw new Error('ui-codemirror needs CodeMirror to work... (o rly?)');
}

return postLink;
}
};

return postLink;
}
};
function postLink(scope, iElement, iAttrs, ngModel) {

function postLink(scope, iElement, iAttrs, ngModel) {
var codemirrorOptions = angular.extend(
{value: iElement.text()},
uiCodemirrorConfig.codemirror || {},
scope.$eval(iAttrs.uiCodemirror),
scope.$eval(iAttrs.uiCodemirrorOpts)
);

var codemirrorOptions = angular.extend(
{ value: iElement.text() },
uiCodemirrorConfig.codemirror || {},
scope.$eval(iAttrs.uiCodemirror),
scope.$eval(iAttrs.uiCodemirrorOpts)
);
var codemirror = newCodemirrorEditor(iElement, codemirrorOptions);

var codemirror = newCodemirrorEditor(iElement, codemirrorOptions);
configOptionsWatcher(
codemirror,
iAttrs.uiCodemirror || iAttrs.uiCodemirrorOpts,
scope
);

configOptionsWatcher(
codemirror,
iAttrs.uiCodemirror || iAttrs.uiCodemirrorOpts,
scope
);
configNgModelLink(codemirror, ngModel, scope);

configUiRefreshAttribute(codemirror, iAttrs.uiRefresh, scope);

// Allow access to the CodeMirror instance through a broadcasted event
// eg: $broadcast('CodeMirror', function(cm){...});
scope.$on('CodeMirror', function(event, callback) {
if (angular.isFunction(callback)) {
callback(codemirror);
} else {
throw new Error('the CodeMirror event requires a callback function');
}
});

configNgModelLink(codemirror, ngModel, scope);
// onLoad callback
if (angular.isFunction(codemirrorOptions.onLoad)) {
codemirrorOptions.onLoad(codemirror);
}
}

configUiRefreshAttribute(codemirror, iAttrs.uiRefresh, scope);
function newCodemirrorEditor(iElement, codemirrorOptions) {
var codemirrot;

// Allow access to the CodeMirror instance through a broadcasted event
// eg: $broadcast('CodeMirror', function(cm){...});
scope.$on('CodeMirror', function(event, callback) {
if (angular.isFunction(callback)) {
callback(codemirror);
if (iElement[0].tagName === 'TEXTAREA') {
// Might bug but still ...
codemirrot = window.CodeMirror.fromTextArea(iElement[0], codemirrorOptions);
} else {
throw new Error('the CodeMirror event requires a callback function');
iElement.html('');
codemirrot = new window.CodeMirror(function(cm_el) {
iElement.append(cm_el);
}, codemirrorOptions);
}
});

// onLoad callback
if (angular.isFunction(codemirrorOptions.onLoad)) {
codemirrorOptions.onLoad(codemirror);
return codemirrot;
}
}

function newCodemirrorEditor(iElement, codemirrorOptions) {
var codemirrot;

if (iElement[0].tagName === 'TEXTAREA') {
// Might bug but still ...
codemirrot = window.CodeMirror.fromTextArea(iElement[0], codemirrorOptions);
} else {
iElement.html('');
codemirrot = new window.CodeMirror(function(cm_el) {
iElement.append(cm_el);
}, codemirrorOptions);
}
function configOptionsWatcher(codemirrot, uiCodemirrorAttr, scope) {
if (!uiCodemirrorAttr) {
return;
}

return codemirrot;
}
var codemirrorDefaultsKeys = Object.keys(window.CodeMirror.defaults);
scope.$watch(uiCodemirrorAttr, updateOptions, true);

function configOptionsWatcher(codemirrot, uiCodemirrorAttr, scope) {
if (!uiCodemirrorAttr) { return; }
function updateOptions(newValues, oldValue) {
if (!angular.isObject(newValues)) {
return;
}
codemirrorDefaultsKeys.forEach(function(key) {
if (newValues.hasOwnProperty(key)) {

var codemirrorDefaultsKeys = Object.keys(window.CodeMirror.defaults);
scope.$watch(uiCodemirrorAttr, updateOptions, true);
function updateOptions(newValues, oldValue) {
if (!angular.isObject(newValues)) { return; }
codemirrorDefaultsKeys.forEach(function(key) {
if (newValues.hasOwnProperty(key)) {
if (oldValue && newValues[key] === oldValue[key]) {
return;
}

if (oldValue && newValues[key] === oldValue[key]) {
return;
codemirrot.setOption(key, newValues[key]);
}
});
}
}

codemirrot.setOption(key, newValues[key]);
function configNgModelLink(codemirror, ngModel, scope) {
if (!ngModel) {
return;
}
// 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;
});
}
}

function configNgModelLink(codemirror, ngModel, scope) {
if (!ngModel) { return; }
// 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);
};

// 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);
};

// Keep the ngModel in sync with changes from CodeMirror
codemirror.on('change', function(instance) {
var newValue = instance.getValue();
if (newValue !== ngModel.$viewValue) {
scope.$evalAsync(function() {
ngModel.$setViewValue(newValue);
});
}
});
}

// Keep the ngModel in sync with changes from CodeMirror
codemirror.on('change', function(instance) {
var newValue = instance.getValue();
if (newValue !== ngModel.$viewValue) {
scope.$evalAsync(function() {
ngModel.$setViewValue(newValue);
});
function configUiRefreshAttribute(codeMirror, uiRefreshAttr, scope) {
if (!uiRefreshAttr) {
return;
}
});
}

function configUiRefreshAttribute(codeMirror, uiRefreshAttr, scope) {
if (!uiRefreshAttr) { return; }
scope.$watch(uiRefreshAttr, function(newVal, oldVal) {
// Skip the initial watch firing
if (newVal !== oldVal) {
$timeout(function() {
codeMirror.refresh();
});
}
});
}

scope.$watch(uiRefreshAttr, function(newVal, oldVal) {
// Skip the initial watch firing
if (newVal !== oldVal) {
$timeout(function() {
codeMirror.refresh();
});
}
});
}

}
}));