Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 9ecff34

Browse files
Merge branch 'master' of github.com:angular/angular.js
2 parents 2450e0b + b6a0777 commit 9ecff34

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+767
-280
lines changed

angularFiles.js

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ angularFiles = {
55
'src/AngularPublic.js',
66
'src/jqLite.js',
77
'src/apis.js',
8+
'src/ngError.js',
89

910
'src/auto/injector.js',
1011

docs/content/guide/dev_guide.unit-testing.ngdoc

+7-19
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,14 @@ app.directive('aGreatEye', function () {
294294
return {
295295
restrict: 'E',
296296
replace: true,
297-
template: '<h1>lidless, wreathed in flame</h1>'
297+
template: '<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>'
298298
};
299299
});
300300
</pre>
301301

302302
This directive is used as a tag `<a-great-eye></a-great-eye>`. It replaces the entire tag with the
303-
template `<h1>lidless, wreathed in flame</h1>`. Now we are going to write a jasmine unit test to
304-
verify this functionality.
303+
template `<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>`. Now we are going to write a jasmine unit test to
304+
verify this functionality. Note that the expression `{{1 + 1}}` times will also be evaluated in the rendered content.
305305

306306
<pre>
307307
describe('Unit testing great quotes', function() {
@@ -322,30 +322,18 @@ describe('Unit testing great quotes', function() {
322322
it('Replaces the element with the appropriate content', function() {
323323
// Compile a piece of HTML containing the directive
324324
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
325+
// fire all the watches, so the scope expression {{1 + 1}} will be evaluated
326+
$rootScope.$digest();
325327
// Check that the compiled element contains the templated content
326-
expect(element.html()).toContain("lidless, wreathed in flame");
328+
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
327329
});
328330
});
329331
</pre>
330332

331333
We inject the $compile service and $rootScope before each jasmine test. The $compile service is used
332334
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
333-
replaced the content and "lidless, wreathed in flame" is present.
335+
replaced the content and "lidless, wreathed in flame, 2 times" is present.
334336

335-
## Mocks
336-
oue
337-
338-
## Global State Isolation
339-
oue
340-
341-
# Preferred way of Testing
342-
uo
343-
344-
## JavaScriptTestDriver
345-
ou
346-
347-
## Jasmine
348-
ou
349337

350338
## Sample project
351339
See the {@link https://github.com/angular/angular-seed angular-seed} project for an example.

docs/spec/ngdocSpec.js

+5
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ describe('ngdoc', function() {
150150
toMatch('</pre>\n\n<h1 id="one">One</h1>\n\n<pre');
151151
});
152152

153+
it('should replace inline variable type hints', function() {
154+
expect(new Doc().markdown('{@type string}')).
155+
toMatch(/<a\s+.*?class=".*?type-hint type-hint-string.*?".*?>/);
156+
});
157+
153158
it('should ignore nested doc widgets', function() {
154159
expect(new Doc().markdown(
155160
'before<div class="tabbable">\n' +

docs/src/ngdoc.js

+4
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ Doc.prototype = {
214214
(title || url).replace(/^#/g, '').replace(/\n/g, ' ') +
215215
(isAngular ? '</code>' : '') +
216216
'</a>';
217+
}).
218+
replace(/{@type\s+(\S+)(?:\s+(\S+))?}/g, function(_, type, url) {
219+
url = url || '#';
220+
return '<a href="' + url + '" class="' + self.prepare_type_hint_class_name(type) + '">' + type + '</a>';
217221
});
218222
});
219223
text = parts.join('');

docs/src/templates/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
<i class="icon-comment icon-white"></i> Discuss <b class="caret"></b>
156156
</a>
157157
<ul class="dropdown-menu">
158+
<li><a href="http://blog.angularjs.org">Blog</a></li>
158159
<li><a href="http://groups.google.com/group/angular">Mailing List</a></li>
159160
<li><a href="http://webchat.freenode.net/?channels=angularjs&uio=d4">Chat Room</a></li>
160161
<li class="divider"></li>

src/Angular.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ function nextUid() {
215215

216216
/**
217217
* Set or clear the hashkey for an object.
218-
* @param obj object
218+
* @param obj object
219219
* @param h the hashkey (!truthy to delete the hashkey)
220220
*/
221221
function setHashKey(obj, h) {
@@ -590,7 +590,10 @@ function isLeafNode (node) {
590590
* @returns {*} The copy or updated `destination`, if `destination` was specified.
591591
*/
592592
function copy(source, destination){
593-
if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope");
593+
if (isWindow(source) || isScope(source)) {
594+
throw ngError(43, "Can't copy! Making copies of Window or Scope instances is not supported.");
595+
}
596+
594597
if (!destination) {
595598
destination = source;
596599
if (source) {
@@ -603,7 +606,7 @@ function copy(source, destination){
603606
}
604607
}
605608
} else {
606-
if (source === destination) throw Error("Can't copy equivalent objects or arrays");
609+
if (source === destination) throw ngError(44, "Can't copy! Source and destination are identical.");
607610
if (isArray(source)) {
608611
destination.length = 0;
609612
for ( var i = 0; i < source.length; i++) {
@@ -1055,7 +1058,7 @@ function bindJQuery() {
10551058
*/
10561059
function assertArg(arg, name, reason) {
10571060
if (!arg) {
1058-
throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
1061+
throw ngError(45, "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
10591062
}
10601063
return arg;
10611064
}

src/auto/injector.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ function createInjector(modulesToLoad) {
422422
},
423423
providerInjector = (providerCache.$injector =
424424
createInternalInjector(providerCache, function() {
425-
throw Error("Unknown provider: " + path.join(' <- '));
425+
throw ngError(1, "Unknown provider: {0}", path.join(' <- '));
426426
})),
427427
instanceCache = {},
428428
instanceInjector = (instanceCache.$injector =
@@ -455,7 +455,7 @@ function createInjector(modulesToLoad) {
455455
provider_ = providerInjector.instantiate(provider_);
456456
}
457457
if (!provider_.$get) {
458-
throw Error('Provider ' + name + ' must define $get factory method.');
458+
throw ngError(2, "Provider '{0}' must define $get factory method.", name);
459459
}
460460
return providerCache[name + providerSuffix] = provider_;
461461
}
@@ -536,12 +536,9 @@ function createInjector(modulesToLoad) {
536536
function createInternalInjector(cache, factory) {
537537

538538
function getService(serviceName) {
539-
if (typeof serviceName !== 'string') {
540-
throw Error('Service name expected');
541-
}
542539
if (cache.hasOwnProperty(serviceName)) {
543540
if (cache[serviceName] === INSTANTIATING) {
544-
throw Error('Circular dependency: ' + path.join(' <- '));
541+
throw ngError(4, 'Circular dependency found: {0}', path.join(' <- '));
545542
}
546543
return cache[serviceName];
547544
} else {
@@ -563,6 +560,9 @@ function createInjector(modulesToLoad) {
563560

564561
for(i = 0, length = $inject.length; i < length; i++) {
565562
key = $inject[i];
563+
if (typeof key !== 'string') {
564+
throw ngError(3, 'Incorrect injection token! Expected service name as string, got {0}', key);
565+
}
566566
args.push(
567567
locals && locals.hasOwnProperty(key)
568568
? locals[key]

src/jqLite.js

+42-29
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ function JQLite(element) {
153153
}
154154
if (!(this instanceof JQLite)) {
155155
if (isString(element) && element.charAt(0) != '<') {
156-
throw Error('selectors not implemented');
156+
throw ngError(46, 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
157157
}
158158
return new JQLite(element);
159159
}
@@ -165,7 +165,8 @@ function JQLite(element) {
165165
div.innerHTML = '<div>&#160;</div>' + element; // IE insanity to make NoScope elements work!
166166
div.removeChild(div.firstChild); // remove the superfluous div
167167
JQLiteAddNodes(this, div.childNodes);
168-
this.remove(); // detach the elements from the temporary DOM div.
168+
var fragment = jqLite(document.createDocumentFragment());
169+
fragment.append(this); // detach the elements from the temporary DOM div.
169170
} else {
170171
JQLiteAddNodes(this, element);
171172
}
@@ -203,11 +204,16 @@ function JQLiteUnbind(element, type, fn) {
203204
}
204205
}
205206

206-
function JQLiteRemoveData(element) {
207+
function JQLiteRemoveData(element, name) {
207208
var expandoId = element[jqName],
208209
expandoStore = jqCache[expandoId];
209210

210211
if (expandoStore) {
212+
if (name) {
213+
delete jqCache[expandoId].data[name];
214+
return;
215+
}
216+
211217
if (expandoStore.handle) {
212218
expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
213219
JQLiteUnbind(element);
@@ -456,24 +462,26 @@ forEach({
456462
}
457463
},
458464

459-
text: extend((msie < 9)
460-
? function(element, value) {
461-
if (element.nodeType == 1 /** Element */) {
462-
if (isUndefined(value))
463-
return element.innerText;
464-
element.innerText = value;
465-
} else {
466-
if (isUndefined(value))
467-
return element.nodeValue;
468-
element.nodeValue = value;
469-
}
465+
text: (function() {
466+
var NODE_TYPE_TEXT_PROPERTY = [];
467+
if (msie < 9) {
468+
NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/
469+
NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/
470+
} else {
471+
NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/
472+
NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/
473+
}
474+
getText.$dv = '';
475+
return getText;
476+
477+
function getText(element, value) {
478+
var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType]
479+
if (isUndefined(value)) {
480+
return textProp ? element[textProp] : '';
470481
}
471-
: function(element, value) {
472-
if (isUndefined(value)) {
473-
return element.textContent;
474-
}
475-
element.textContent = value;
476-
}, {$dv:''}),
482+
element[textProp] = value;
483+
}
484+
})(),
477485

478486
val: function(element, value) {
479487
if (isUndefined(value)) {
@@ -518,8 +526,14 @@ forEach({
518526
return this;
519527
} else {
520528
// we are a read, so read the first child.
521-
if (this.length)
522-
return fn(this[0], arg1, arg2);
529+
var value = fn.$dv;
530+
// Only if we have $dv do we iterate over all, otherwise it is just the first element.
531+
var jj = value == undefined ? Math.min(this.length, 1) : this.length;
532+
for (var j = 0; j < jj; j++) {
533+
var nodeValue = fn(this[j], arg1, arg2);
534+
value = value ? value + nodeValue : nodeValue;
535+
}
536+
return value;
523537
}
524538
} else {
525539
// we are a write, so apply to all children
@@ -529,7 +543,6 @@ forEach({
529543
// return self for chaining
530544
return this;
531545
}
532-
return fn.$dv;
533546
};
534547
});
535548

@@ -627,22 +640,22 @@ forEach({
627640
}
628641
}
629642
return false;
630-
};
643+
};
631644

632645
events[type] = [];
633-
634-
// Refer to jQuery's implementation of mouseenter & mouseleave
646+
647+
// Refer to jQuery's implementation of mouseenter & mouseleave
635648
// Read about mouseenter and mouseleave:
636649
// http://www.quirksmode.org/js/events_mouse.html#link8
637-
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}
650+
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
651+
638652
bindFn(element, eventmap[type], function(event) {
639653
var ret, target = this, related = event.relatedTarget;
640654
// For mousenter/leave call the handler if related is outside the target.
641655
// NB: No relatedTarget if the mouse left/entered the browser window
642656
if ( !related || (related !== target && !contains(target, related)) ){
643657
handle(event, type);
644-
}
645-
658+
}
646659
});
647660

648661
} else {

src/loader.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function setupModuleLoader(window) {
7070
}
7171
return ensure(modules, name, function() {
7272
if (!requires) {
73-
throw Error('No module: ' + name);
73+
throw ngError(47, "Module '{0}' is not available! You either misspelled the module name or forgot to load it.", name);
7474
}
7575

7676
/** @type {!Array.<Array.<*>>} */

src/ng/animator.js

+31-24
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ var $AnimatorProvider = function() {
262262
* @description
263263
* Triggers a custom animation event to be executed on the given element
264264
*
265-
* @param {jQuery/jqLite element} element that will be animated
265+
* @param {string} event the name of the custom event
266+
* @param {jQuery/jqLite element} element the element that will be animated
266267
*/
267268
animator.animate = function(event, element) {
268269
animateActionFactory(event, noop, noop)(element);
@@ -344,28 +345,29 @@ var $AnimatorProvider = function() {
344345
var ELEMENT_NODE = 1;
345346
forEach(element, function(element) {
346347
if (element.nodeType == ELEMENT_NODE) {
347-
var w3cProp = w3cTransitionProp,
348-
vendorProp = vendorTransitionProp,
349-
iterations = 1,
350-
elementStyles = $window.getComputedStyle(element) || {};
348+
var elementStyles = $window.getComputedStyle(element) || {};
351349

352-
//use CSS Animations over CSS Transitions
353-
if(parseFloat(elementStyles[w3cAnimationProp + durationKey]) > 0 ||
354-
parseFloat(elementStyles[vendorAnimationProp + durationKey]) > 0) {
355-
w3cProp = w3cAnimationProp;
356-
vendorProp = vendorAnimationProp;
357-
iterations = Math.max(parseInt(elementStyles[w3cProp + animationIterationCountKey]) || 0,
358-
parseInt(elementStyles[vendorProp + animationIterationCountKey]) || 0,
359-
iterations);
360-
}
350+
var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]),
351+
parseMaxTime(elementStyles[vendorTransitionProp + delayKey]));
352+
353+
var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]),
354+
parseMaxTime(elementStyles[vendorAnimationProp + delayKey]));
355+
356+
var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]),
357+
parseMaxTime(elementStyles[vendorTransitionProp + durationKey]));
361358

362-
var parsedDelay = Math.max(parseMaxTime(elementStyles[w3cProp + delayKey]),
363-
parseMaxTime(elementStyles[vendorProp + delayKey]));
359+
var animationDuration = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + durationKey]),
360+
parseMaxTime(elementStyles[vendorAnimationProp + durationKey]));
364361

365-
var parsedDuration = Math.max(parseMaxTime(elementStyles[w3cProp + durationKey]),
366-
parseMaxTime(elementStyles[vendorProp + durationKey]));
362+
if(animationDuration > 0) {
363+
animationDuration *= Math.max(parseInt(elementStyles[w3cAnimationProp + animationIterationCountKey]) || 0,
364+
parseInt(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0,
365+
1);
366+
}
367367

368-
duration = Math.max(parsedDelay + (iterations * parsedDuration), duration);
368+
duration = Math.max(animationDelay + animationDuration,
369+
transitionDelay + transitionDuration,
370+
duration);
369371
}
370372
});
371373
$window.setTimeout(done, duration * 1000);
@@ -395,11 +397,16 @@ var $AnimatorProvider = function() {
395397
}
396398

397399
function insert(element, parent, after) {
398-
if (after) {
399-
after.after(element);
400-
} else {
401-
parent.append(element);
402-
}
400+
var afterNode = after && after[after.length - 1];
401+
var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
402+
var afterNextSibling = afterNode && afterNode.nextSibling;
403+
forEach(element, function(node) {
404+
if (afterNextSibling) {
405+
parentNode.insertBefore(node, afterNextSibling);
406+
} else {
407+
parentNode.appendChild(node);
408+
}
409+
});
403410
}
404411

405412
function remove(element) {

0 commit comments

Comments
 (0)