changeset in labs/bespinclient: fix bug 586856: problem with Chr...

2 views
Skip to first unread message

Kevin Dangoor

unread,
Aug 12, 2010, 9:48:08 PM8/12/10
to bespin-...@googlegroups.com
changeset 779c4adb9c08 in /repo/hg/mozilla/labs/bespinclient
details: http://hg.mozilla.org/labs/bespinclient?cmd=changeset;node=779c4adb9c08
description:
fix bug 586856: problem with Chrome 6.0dev and Traits.js

diffstat:

plugins/thirdparty/traits.js | 252 ++++++++++++++++++++++++++++--------------
1 files changed, 169 insertions(+), 83 deletions(-)

diffs (truncated from 437 to 300 lines):

diff --git a/plugins/thirdparty/traits.js b/plugins/thirdparty/traits.js
--- a/plugins/thirdparty/traits.js
+++ b/plugins/thirdparty/traits.js
@@ -23,49 +23,101 @@
});
"end";

-// --- Begin traits-0.1.js ---
+// --- Begin traits-0.3.js ---

-exports.Trait = (function(){
+// Copyright (C) 2010 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// See http://code.google.com/p/es-lab/wiki/Traits
+// for background on traits and a description of this library
+
+var Trait = (function(){

// == Ancillary functions ==

- // this signals that the current ES implementation supports properties,
- // so probably also accessor properties
- var SUPPORTS_DEFINEPROP = !!Object.defineProperty;
+ var SUPPORTS_DEFINEPROP = (function() {
+ try {
+ var test = {};
+ Object.defineProperty(test, 'x', {get: function() { return 0; } } );
+ return test.x === 0;
+ } catch(e) {
+ return false;
+ }
+ })();
+
+ // IE8 implements Object.defineProperty and Object.getOwnPropertyDescriptor
+ // only for DOM objects. These methods don't work on plain objects.
+ // Hence, we need a more elaborate feature-test to see whether the
+ // browser truly supports these methods:
+ function supportsGOPD() {
+ try {
+ if (Object.getOwnPropertyDescriptor) {
+ var test = {x:0};
+ return !!Object.getOwnPropertyDescriptor(test,'x');
+ }
+ } catch(e) {}
+ return false;
+ };
+ function supportsDP() {
+ try {
+ if (Object.defineProperty) {
+ var test = {};
+ Object.defineProperty(test,'x',{value:0});
+ return test.x === 0;
+ }
+ } catch(e) {}
+ return false;
+ };

var call = Function.prototype.call;

/**
* An ad hoc version of bind that only binds the 'this' parameter.
*/
- var bindThis = Function.prototype.bind
- ? function(fun, self) { return Function.prototype.bind.call(fun, self); }
- : function(fun, self) {
- function funcBound(var_args) {
- return fun.apply(self, arguments);
- }
- return funcBound;
- };
+ var bindThis = Function.prototype.bind ?
+ function(fun, self) { return Function.prototype.bind.call(fun, self); } :
+ function(fun, self) {
+ function funcBound(var_args) {
+ return fun.apply(self, arguments);
+ }
+ return funcBound;
+ };

var hasOwnProperty = bindThis(call, Object.prototype.hasOwnProperty);
var slice = bindThis(call, Array.prototype.slice);

// feature testing such that traits.js runs on both ES3 and ES5
- var forEach = Array.prototype.forEach
- ? bindThis(call, Array.prototype.forEach)
- : function(arr, fun) {
- for (var i = 0, len = arr.length; i < len; i++) { fun(arr[i]); }
- };
-
- var freeze = Object.freeze || function(obj) { return obj; };
- var getPrototypeOf = Object.getPrototypeOf || function(obj) { return Object.prototype };
+ var forEach = Array.prototype.forEach ?
+ bindThis(call, Array.prototype.forEach) :
+ function(arr, fun) {
+ for (var i = 0, len = arr.length; i < len; i++) { fun(arr[i]); }
+ };
+
+ // on v8 version 2.3.4.1, Object.freeze(obj) returns undefined instead of obj
+ var freeze = (Object.freeze ? function(obj) { Object.freeze(obj); return obj; }
+ : function(obj) { return obj; });
+ var getPrototypeOf = Object.getPrototypeOf || function(obj) {
+ return Object.prototype;
+ };
var getOwnPropertyNames = Object.getOwnPropertyNames ||
function(obj) {
var props = [];
for (var p in obj) { if (hasOwnProperty(obj,p)) { props.push(p); } }
return props;
};
- var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor ||
+ var getOwnPropertyDescriptor = supportsGOPD() ?
+ Object.getOwnPropertyDescriptor :
function(obj, name) {
return {
value: obj[name],
@@ -74,7 +126,7 @@ exports.Trait = (function(){
configurable: true
};
};
- var defineProperty = Object.defineProperty ||
+ var defineProperty = supportsDP() ? Object.defineProperty :
function(obj, name, pd) {
obj[name] = pd.value;
};
@@ -159,7 +211,8 @@ exports.Trait = (function(){

// Note: isSameDesc should return true if both
// desc1 and desc2 represent a 'required' property
- // (otherwise two composed required properties would be turned into a conflict)
+ // (otherwise two composed required properties would be turned into
+ // a conflict)
function isSameDesc(desc1, desc2) {
// for conflicting properties, don't compare values because
// the conflicting property values are never equal
@@ -196,9 +249,12 @@ exports.Trait = (function(){
return freeze(set);
}

- // == singleton object to be used as the placeholder for a required property ==
+ // == singleton object to be used as the placeholder for a required
+ // property ==

- var required = freeze({ toString: function() { return '<Trait.required>'; } });
+ var required = freeze({
+ toString: function() { return '<Trait.required>'; }
+ });

// == The public API methods ==

@@ -209,20 +265,23 @@ exports.Trait = (function(){
* @returns a new trait describing all of the own properties of the object
* (both enumerable and non-enumerable)
*
- * As a general rule, 'trait' should be invoked with an
- * object literal, since the object merely serves as a record
- * descriptor. Both its identity and its prototype chain are irrelevant.
+ * As a general rule, 'trait' should be invoked with an object
+ * literal, since the object merely serves as a record
+ * descriptor. Both its identity and its prototype chain are
+ * irrelevant.
*
- * Data properties bound to function objects in the argument will be flagged
- * as 'method' properties. The prototype of these function objects is frozen.
+ * Data properties bound to function objects in the argument will be
+ * flagged as 'method' properties. The prototype of these function
+ * objects is frozen.
*
- * Data properties bound to the 'required' singleton exported by this module
- * will be marked as 'required' properties.
+ * Data properties bound to the 'required' singleton exported by
+ * this module will be marked as 'required' properties.
*
- * The <tt>trait</tt> function is pure if no other code can witness the
- * side-effects of freezing the prototypes of the methods. If <tt>trait</tt>
- * is invoked with an object literal whose methods are represented as
- * in-place anonymous functions, this should normally be the case.
+ * The <tt>trait</tt> function is pure if no other code can witness
+ * the side-effects of freezing the prototypes of the methods. If
+ * <tt>trait</tt> is invoked with an object literal whose methods
+ * are represented as in-place anonymous functions, this should
+ * normally be the case.
*/
function trait(obj) {
var map = {};
@@ -270,15 +329,18 @@ exports.Trait = (function(){
if (hasOwnProperty(newTrait, name) &&
!newTrait[name].required) {

- // a non-required property with the same name was previously defined
- // this is not a conflict if pd represents a 'required' property itself:
+ // a non-required property with the same name was previously
+ // defined this is not a conflict if pd represents a
+ // 'required' property itself:
if (pd.required) {
- return; // skip this property, the required property is now present
+ return; // skip this property, the required property is
+ // now present
}

if (!isSameDesc(newTrait[name], pd)) {
// a distinct, non-required property with the same name
- // was previously defined by another trait => mark as conflicting property
+ // was previously defined by another trait => mark as
+ // conflicting property
newTrait[name] = makeConflictingPropDesc(name);
} // else,
// properties are not in conflict if they refer to the same value
@@ -322,16 +384,18 @@ exports.Trait = (function(){
/**
* var newTrait = override(trait_1, trait_2, ..., trait_N)
*
- * @returns a new trait with all of the combined properties of the argument traits.
- * In contrast to 'compose', 'override' immediately resolves all conflicts
- * resulting from this composition by overriding the properties of later
- * traits. Trait priority is from left to right. I.e. the properties of the
- * leftmost trait are never overridden.
+ * @returns a new trait with all of the combined properties of the
+ * argument traits. In contrast to 'compose', 'override'
+ * immediately resolves all conflicts resulting from this
+ * composition by overriding the properties of later
+ * traits. Trait priority is from left to right. I.e. the
+ * properties of the leftmost trait are never overridden.
*
* override is associative:
* override(t1,t2,t3) is equivalent to override(t1, override(t2, t3)) or
* to override(override(t1, t2), t3)
- * override is not commutative: override(t1,t2) is not equivalent to override(t2,t1)
+ * override is not commutative: override(t1,t2) is not equivalent
+ * to override(t2,t1)
*
* override() returns an empty trait
* override(trait_1) returns a trait equivalent to trait_1
@@ -360,7 +424,8 @@ exports.Trait = (function(){
* and all of the properties of recessiveTrait not in dominantTrait
*
* Note: override is associative:
- * override(t1, override(t2, t3)) is equivalent to override(override(t1, t2), t3)
+ * override(t1, override(t2, t3)) is equivalent to
+ * override(override(t1, t2), t3)
*/
/*function override(frontT, backT) {
var newTrait = {};
@@ -395,12 +460,14 @@ exports.Trait = (function(){
* { a: { required: true },
* b: t[a] })
*
- * For each renamed property, a required property is generated.
- * If the map renames two properties to the same name, a conflict is generated.
- * If the map renames a property to an existing unrenamed property, a conflict is generated.
+ * For each renamed property, a required property is generated. If
+ * the map renames two properties to the same name, a conflict is
+ * generated. If the map renames a property to an existing
+ * unrenamed property, a conflict is generated.
*
- * Note: rename(A, rename(B, t)) is equivalent to rename(\n -> A(B(n)), t)
- * Note: rename({...},exclude([...], t)) is not eqv to exclude([...],rename({...}, t))
+ * Note: rename(A, rename(B, t)) is equivalent to rename(\n ->
+ * A(B(n)), t) Note: rename({...},exclude([...], t)) is not eqv to
+ * exclude([...],rename({...}, t))
*/
function rename(map, trait) {
var renamedTrait = {};
@@ -408,7 +475,8 @@ exports.Trait = (function(){
// required props are never renamed
if (hasOwnProperty(map, name) && !trait[name].required) {
var alias = map[name]; // alias defined in map
- if (hasOwnProperty(renamedTrait, alias) && !renamedTrait[alias].required) {
+ if (hasOwnProperty(renamedTrait, alias) &&
+ !renamedTrait[alias].required) {
// could happen if 2 props are mapped to the same alias
renamedTrait[alias] = makeConflictingPropDesc(alias);
} else {
@@ -417,8 +485,8 @@ exports.Trait = (function(){
}
// add a required property under the original name
// but only if a property under the original name does not exist
- // such a prop could exist if an earlier prop in the trait was previously
- // aliased to this name
+ // such a prop could exist if an earlier prop in the trait was
+ // previously aliased to this name
if (!hasOwnProperty(renamedTrait, name)) {
renamedTrait[name] = makeRequiredPropDesc(name);
}
@@ -428,8 +496,8 @@ exports.Trait = (function(){
if (!trait[name].required) {
renamedTrait[name] = makeConflictingPropDesc(name);
}
- // else required property overridden by a previously aliased property

Reply all
Reply to author
Forward
0 new messages