add($compile): add compiler v2.0 - not connected

This commit is contained in:
Misko Hevery 2011-11-29 12:11:32 -08:00
parent 5001c1a121
commit 8af4fde182
10 changed files with 2019 additions and 572 deletions

View file

@ -626,6 +626,22 @@ function copy(source, destination){
return destination; return destination;
} }
/**
* Create a shallow copy of an object
* @param src
*/
function shallowCopy(src) {
var dst = {},
key;
for(key in src) {
if (src.hasOwnProperty(key)) {
dst[key] = src[key];
}
}
return dst;
}
/** /**
* @ngdoc function * @ngdoc function
* @name angular.equals * @name angular.equals
@ -750,6 +766,19 @@ function toBoolean(value) {
return value; return value;
} }
/**
* @returns {string} Returns the string representation of the element.
*/
function startingTag(element) {
element = jqLite(element).clone();
try {
// turns out IE does not let you set .html() on elements which
// are not allowed to have children. So we just ignore it.
element.html('');
} catch(e) {};
return jqLite('<div>').append(element).html().replace(/\<\/[\w\:\-]+\>$/, '');
}
///////////////////////////////////////////////// /////////////////////////////////////////////////
@ -918,6 +947,14 @@ function bootstrap(element, modules) {
return injector; return injector;
} }
var SNAKE_CASE_REGEXP = /[A-Z]/g;
function snake_case(name, separator){
separator = separator || '_';
return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
return (pos ? separator : '') + letter.toLowerCase();
});
}
function bindJQuery() { function bindJQuery() {
// bind to jQuery if present; // bind to jQuery if present;
jQuery = window.jQuery; jQuery = window.jQuery;
@ -951,6 +988,7 @@ function assertArg(arg, name, reason) {
} }
function assertArgFn(arg, name) { function assertArgFn(arg, name) {
assertArg(arg, name);
assertArg(isFunction(arg), name, 'not a function, got ' + assertArg(isFunction(arg), name, 'not a function, got ' +
(typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg)); (typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
return arg; return arg;

12
src/angular-mocks.js vendored
View file

@ -684,19 +684,17 @@ angular.mock.dump = function(object) {
* *
* <pre> * <pre>
// controller // controller
function MyController($http) { function MyController($scope, $http) {
var scope = this;
$http.get('/auth.py').success(function(data) { $http.get('/auth.py').success(function(data) {
scope.user = data; $scope.user = data;
}); });
this.saveMessage = function(message) { this.saveMessage = function(message) {
scope.status = 'Saving...'; $scope.status = 'Saving...';
$http.post('/add-msg.py', message).success(function(response) { $http.post('/add-msg.py', message).success(function(response) {
scope.status = ''; $scope.status = '';
}).error(function() { }).error(function() {
scope.status = 'ERROR!'; $scope.status = 'ERROR!';
}); });
}; };
} }

View file

@ -100,13 +100,27 @@ function getStyle(element) {
} }
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
/** /**
* Converts dash-separated names to camelCase. Useful for dealing with css properties. * Converts all accepted directives format into proper directive name.
* All of these will become 'myDirective':
* my:DiRective
* my-directive
* x-my-directive
* data-my:directive
*
* Also there is special case for Moz prefix starting with upper case letter.
* @param name Name to normalize
*/ */
function camelCase(name) { function camelCase(name) {
return name.replace(/\-(\w)/g, function(all, letter, offset){ return name.
return (offset == 0 && letter == 'w') ? 'w' : letter.toUpperCase(); replace(PREFIX_REGEXP, '').
}); replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
return offset ? letter.toUpperCase() : letter;
}).
replace(MOZ_HACK_REGEXP, 'Moz$1');
} }
///////////////////////////////////////////// /////////////////////////////////////////////

File diff suppressed because it is too large Load diff

View file

@ -56,41 +56,43 @@
}); });
} }
angular.directive('ng:contenteditable', function() { angular.module('formModule', [], function($compileProvider){
return ['$formFactory', '$element', function ($formFactory, element) { $compileProvider.directive('ngHtmlEditorModel', function ($formFactory) {
var exp = element.attr('ng:contenteditable'), return function(scope, element, attr) {
form = $formFactory.forElement(element), var form = $formFactory.forElement(element),
widget; widget;
element.attr('contentEditable', true); element.attr('contentEditable', true);
widget = form.$createWidget({ widget = form.$createWidget({
scope: this, scope: scope,
model: exp, model: attr.ngHtmlEditorModel,
controller: HTMLEditorWidget, controller: HTMLEditorWidget,
controllerArgs: {$element: element}}); controllerArgs: {$element: element}});
// if the element is destroyed, then we need to notify the form. // if the element is destroyed, then we need to
element.bind('$destroy', function() { // notify the form.
widget.$destroy(); element.bind('$destroy', function() {
}); widget.$destroy();
}]; });
}); };
</script> });
<form name='editorForm' ng:controller="EditorCntl"> });
<div ng:contenteditable="html"></div> </script>
<hr/> <form name='editorForm' ng:controller="EditorCntl">
HTML: <br/> <div ng:html-editor-model="htmlContent"></div>
<textarea ng:model="html" cols=80></textarea> <hr/>
<hr/> HTML: <br/>
<pre>editorForm = {{editorForm}}</pre> <textarea ng:model="htmlContent" cols="80"></textarea>
</form> <hr/>
</doc:source> <pre>editorForm = {{editorForm|json}}</pre>
<doc:scenario> </form>
it('should enter invalid HTML', function() { </doc:source>
expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-valid/); <doc:scenario>
input('html').enter('<'); it('should enter invalid HTML', function() {
expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-invalid/); expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-valid/);
}); input('htmlContent').enter('<');
</doc:scenario> expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-invalid/);
</doc:example> });
</doc:scenario>
</doc:example>
*/ */
/** /**

View file

@ -75,6 +75,22 @@ describe('angular', function() {
}); });
}); });
describe('shallow copy', function() {
it('should make a copy', function() {
var original = {key:{}};
var copy = shallowCopy(original);
expect(copy).toEqual(original);
expect(copy.key).toBe(original.key);
});
});
describe('elementHTML', function() {
it('should dump element', function() {
expect(lowercase(startingTag('<div attr="123">something<span></span></div>'))).
toEqual('<div attr="123">');
});
});
describe('equals', function() { describe('equals', function() {
it('should return true if same object', function() { it('should return true if same object', function() {
var o = {}; var o = {};
@ -501,4 +517,11 @@ describe('angular', function() {
dealoc(element); dealoc(element);
}); });
}); });
describe('startingElementHtml', function(){
it('should show starting element tag only', function(){
expect(startingTag('<ng:abc x="2"><div>text</div></ng:abc>')).toEqual('<ng:abc x="2">');
});
});
}); });

View file

@ -2,14 +2,18 @@
describe("directive", function() { describe("directive", function() {
var $filterProvider; var $filterProvider, element;
beforeEach(module(['$filterProvider', function(provider){ beforeEach(module(['$filterProvider', function(provider){
$filterProvider = provider; $filterProvider = provider;
}])); }]));
afterEach(function() {
dealoc(element);
});
it("should ng:init", inject(function($rootScope, $compile) { it("should ng:init", inject(function($rootScope, $compile) {
var element = $compile('<div ng:init="a=123"></div>')($rootScope); element = $compile('<div ng:init="a=123"></div>')($rootScope);
expect($rootScope.a).toEqual(123); expect($rootScope.a).toEqual(123);
})); }));

View file

@ -1,4 +1,3 @@
'use strict';
describe('jqLite', function() { describe('jqLite', function() {
var scope, a, b, c; var scope, a, b, c;
@ -880,6 +879,7 @@ describe('jqLite', function() {
it('should covert dash-separated strings to camelCase', function() { it('should covert dash-separated strings to camelCase', function() {
expect(camelCase('foo-bar')).toBe('fooBar'); expect(camelCase('foo-bar')).toBe('fooBar');
expect(camelCase('foo-bar-baz')).toBe('fooBarBaz'); expect(camelCase('foo-bar-baz')).toBe('fooBarBaz');
expect(camelCase('foo:bar_baz')).toBe('fooBarBaz');
}); });

File diff suppressed because it is too large Load diff

View file

@ -67,7 +67,10 @@ function dealoc(obj) {
} }
} }
/**
* @param {DOMElement} element
* @param {boolean=} showNgClass
*/
function sortedHtml(element, showNgClass) { function sortedHtml(element, showNgClass) {
var html = ""; var html = "";
forEach(jqLite(element), function toString(node) { forEach(jqLite(element), function toString(node) {