ibm-js / decor Goto Github PK
View Code? Open in Web Editor NEWUtility classes and functions used by ibm-js. Non-widget, non-UI related functionality.
License: Other
Utility classes and functions used by ibm-js. Non-widget, non-UI related functionality.
License: Other
decor should require requirejs-dplugins
with version 0.2.x
.
The refreshRendering method is called on private attributes change. This is not the case on FF or IE.
This explains ibm-js/deliteful#220.
To reproduce, you can use the following test files:
deliteful/DebugWidget.js
define([
"dcl/dcl",
"delite/register",
"delite/Widget",
],
function (dcl, register, Widget) {
return register("d-debug-widget", [HTMLElement, Widget], {
baseClass: "d-debug-widget",
_privateProperty: 1,
buildRendering: function () {
console.log("build");
},
refreshRendering: function (props) {
console.log("refresh", props);
},
callMe: function () {
console.log("call");
this._privateProperty = 0;
}
});
});
deliteful/samples/DebugWidget.html
<!doctype html>
<html>
<head>
<script type="text/javascript" src="../../requirejs/require.js"></script>
<script type="text/javascript">require.config({baseUrl: "../.."});</script>
<script type="text/javascript">
require([
"delite/register",
"deliteful/DebugWidget"
], function(register){
register.parse();
});
</script>
</head>
<body>
<d-debug-widget id="dw" style="background-color: yellow;" onClick="dw.callMe()">
Click Me
</d-debug-widget>
</body>
</html>
Result on Chrome 36:
build
refresh Object {_created: undefined, _attached: undefined, _started: undefined}
-- Click on the Widget --
call
refresh Object {_privateProperty: undefined}
Result on FF/IE:
build
-- Click on the Widget --
call
Consider adding safeguards so observe() doesn't "hang" when a property points to an HTMLElement, for example:
var observe = require("decor/observe");
var pojo = {
a: 1,
b: null
};
observe(pojo, function (oldValues) {
console.log(oldValues);
});
pojo.b = document.createElement("div");
Stateful#observe() and Destroyable#own() automatically bind the callback to this
... which was a nice feature until ES6 came along.
Now, code like this has unexpected results:
const MyClass = dcl (null, {
myWidget: ...,
myMethod: function () {
this.myWidget.observe(props => console.log(this));
}
}
```
In the above code it's natural to assume that the `console.log(this)` will print`MyClass`, but it actually refers to `myWidget`,
Create observe() and bind() modules for programatic binding from POJOs to Stateful subclasses.
observe()
is similar to Stateful#observe()
but works on plain POJOs.
From another ange, the main difference between observe()
and Observable#observe()
is that the former:
observe()
will (at least initially) report changed properties in an oldValues
hash, same as decor/Stateful.
bind() is similar in functionality to liaison's ObservablePath, with the difference that it works on POJOs.
Deliteful/Slider calls .deliver() from startup():
// force immediate validation, otherwise in certain cases a call to slider.value returns the default
// value declared in the markup instead of the calculated default value.
this.deliver();
For consistency, should we be calling deliver() from Invalidating instead? I think this will work:
attachedCallback: dcl.before(function () {
this.deliver();
}),
Note also that LinearLayout calls deliver() from buildRendering(). That's presumably to update the CSS classes, but it's presumably a mistake because there's no notifyCurrentValue("vertical") call.
PS: Also, StarRating#createdCallback()
calls this.refreshRendering(this)
directly.
cc @asudoh
decor/features.js has this line:
has.add("object-is-api", Object.is);
It's not operating as expected because Object.is
is a function, and has.add(string, function)
has different behavior than has.add(string, boolean)
. Effectively the code above does:
has.add("object-is-api", Object.is(window));
The result is that, even on Chrome, has("object-is-api")
evaluates to false, and the native Object.is()
is not used.
Should probably just change the above code to:
has.add("object-is-api", typeof Object.is === "function");
That matches the other has.add() calls in that file. But of course it needs to be tested.
The README.md has a section for dependencies w/nothing listed. It should either list jQuery (currently used by css.js), or lie (if css.js is upgraded to use lie rather than jquery for its promises).
Or better yet, why not remove the dependencies sections from the README file since they duplicate info from bower.json and since they get out of date?
See ibm-js/delite#230, that was open by error on delite.
http://ibm-js.github.io/decor/docs/master/index.html
is lacking links in particular to:
http://ibm-js.github.io/decor/docs/master/Invalidating.html
(see how delite or deliteful has done it in docs/index.md)
The function remove of the result of Observable.observe return the object where the observability has been removed on native implementation of Chrome.
It is not the case of the one define in Observable.js.
I do not know if it is wanted or not, but it is quite useful in Chrome to test if we have removed the observability on the good object.
See test Store-ArrayObs in harbalk/delite@46e3e5c
assert.deepEqual(store._itemHandles[0].remove(), { id: "bar", name: "Bar" });
assert.deepEqual(store._itemHandles[1].remove(), { id: "fb", name: "FB" });
On iOS 13.1 and iOS 13.2, Safari has a bizarre navigator.userAgent
of:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15
This is almost exactly the same as on Safari/mac, which is:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15
As such, the following has()
flags have the wrong values:
has("mac")
--> true
(should be false
)has("ios")
--> undefined
(should be 13
)has("ipod")
, has("iphone")
, has("ipad")
- undefined
(one of them should be 13
)Note: the user agent on iOS 13.0 seems to be ok, see https://qiita.com/niwasawa/items/df30ffddf2e709b2ca43.
Destroyable#own()
was designed to try to handle objects with multiple "aliases" for destruction. Objects like Stateful.PropertyListObserver
that has both remove()
and close()
methods that do the same thing, or the handle returned from dcl.advise()
that has both destroy()
and unadvise()
methods that do the same thing.
The problem is that some dstore
subclasses have both destroy()
and remove()
methods, but the remove()
method does NOT destroy the store, but rather just removes an item from the store. In that case, Destroyable#own()
needs to continue tracking the store.
I guess own()
should be changed to just monitor calls to the first matching method from the list. (The list is currently destroy
, remove
, and cancel
.)
Since the commit 51afb50 was introduced, I can't seem to be able to initialize a widget: I keep getting theses exceptions.
You can reproduce it by loading any sample from delite or deliteful.
As @cjolif mentioned to me, with bower 1.3.7, you can't install decor. It worked with 1.3.5.
@asudoh any idea how to fix?
mac:delite bill$ bower install decor
bower not-cached git://github.com/ibm-js/decor.git#master
bower resolve git://github.com/ibm-js/decor.git#master
bower not-cached git://github.com/ibm-js/decor.git#*
bower resolve git://github.com/ibm-js/decor.git#*
bower checkout decor#master
bower checkout decor#master
bower error Arguments to path.join must be strings
Stack trace:
TypeError: Arguments to path.join must be strings
at path.js:360:15
at Array.filter (native)
at Object.exports.join (path.js:358:36)
at GitHubResolver.GitResolver._cleanup (/usr/local/lib/node_modules/bower/lib/core/resolvers/GitResolver.js:197:26)
at /usr/local/lib/node_modules/bower/lib/core/resolvers/GitResolver.js:74:25
at Promise.apply (/usr/local/lib/node_modules/bower/node_modules/p-throttler/node_modules/q/q.js:1122:26)
at Promise.promise.promiseDispatch (/usr/local/lib/node_modules/bower/node_modules/p-throttler/node_modules/q/q.js:752:41)
at /usr/local/lib/node_modules/bower/node_modules/p-throttler/node_modules/q/q.js:1337:14
at flush (/usr/local/lib/node_modules/bower/node_modules/p-throttler/node_modules/q/q.js:108:17)
at process._tickCallback (node.js:415:13)
Console trace:
Trace
at StandardRenderer.error (/usr/local/lib/node_modules/bower/lib/renderers/StandardRenderer.js:72:17)
at Logger.<anonymous> (/usr/local/lib/node_modules/bower/bin/bower:111:22)
at Logger.EventEmitter.emit (events.js:95:17)
at Logger.emit (/usr/local/lib/node_modules/bower/node_modules/bower-logger/lib/Logger.js:29:39)
at /usr/local/lib/node_modules/bower/lib/commands/index.js:40:20
at _rejected (/usr/local/lib/node_modules/bower/node_modules/q/q.js:797:24)
at /usr/local/lib/node_modules/bower/node_modules/q/q.js:823:30
at Promise.when (/usr/local/lib/node_modules/bower/node_modules/q/q.js:1035:31)
at Promise.promise.promiseDispatch (/usr/local/lib/node_modules/bower/node_modules/q/q.js:741:41)
at /usr/local/lib/node_modules/bower/node_modules/q/q.js:557:44
System info:
Bower version: 1.3.7
Node version: 0.10.26
OS: Darwin 13.3.0 x64
I wonder why this file is empty.
I originally wrote Stateful to not monitor changes to underscore properties. The reason was performance: to avoid creating custom setters/getters for those private properties (albeit just on the prototype, not on each instance), and more importantly, to avoid having to call a custom setter every time you set a private property.
The idea was that all properties would be underscore except for ones the user sets/gets directly, i.e. the public properties.
In practice, this hasn't worked out well, because people insist on naming protected properties without an underscore; not for technical reasons, but merely for coding style. Also, because any property referenced in a template, or from computeProperties() or refreshRendering(), needs to be monitored.
Finally, note that you can make an unmonitored property with or without an underscore by not putting it in the prototype and merely setting it in preCreate(), etc.
So, probably we should add notification for underscore properties?
The reason to remove the special case is so people don't complain that something is broken/hard to use because their underscore property changes aren't getting reported.
Complementary to ibm-js/delite#385, we should probably call deliver() automatically when an Invalidating subclass has been instantiated.
refreshRendering()
and computeProperties()
are typically used like constructor()
, postCreate()
and startup()
. I.e.: Every class in the inheritance chain gets to define its own refreshRendering()
method and they should all be run when an instance's properties are changed
Therefore, probably it makes sense to auto-chain these methods, same as postCreate
:
dcl.chainAfter(Invalidating, "computeProperties");
dcl.chainAfter(Invalidating, "refreshRendering");
The advantage is that subclasses don't need to call dcl.superCall()
or dcl.after()
to run the superclasses' methods. In the hypothetical exceptional case where a subclass wants to stop the superclasses' method from running, it can use dcl.superCall()
.
There are 2 places in the decor API where protected members start with "_". Per our guidelines, this naming convention should be for internal/private member, and should not be used for protected members.
This is the decor counter-part of ibm-js/delite#280 and ibm-js/deliteful#291.
The 2 occurrences are Stateful, for its _set
and _get
members. However, not sure if just removing the underscore prefix would be a safe way to go (potential risk of clash?).
Currently, has("android") returns undefined on any non-webkit browser on Android (for instance, Firefox / Nexus 5 / Android 5) and has("ios") returns undefined on any non-webkit browser on iOS. This is because https://github.com/ibm-js/decor/blob/master/sniff.js runs the platform detection for Android and iOS only if the browser is found to be a webkit browsers.
Regardless of whether we support some combination of browser and platform, I think it would be saner to uncouple the platform detection from the webkit detection. At least I don't see a good reason to keep it coupled.
Since firefox is our only officially supported mozilla based browser, remove the has("mozilla")
flag. Code should just use has("ff")
(or if feasible, a feature test).
Our rule is that only private methods/properties should have underscores. Therefore _set(), _get(), _setFooAttr() etc. probably shouldn't have underscores.
set()
and get()
though are confusing renames, since _set("foo", ...)
doesn't call the custom setter for foo
, but rather just saves the value of the shadow property (and IIRC triggers a call to observers). And likewise for _get()
. So maybe name them something else.
There aren't many _setFooAttr()
type methods since we usually do processing in computeProperties()
and refreshRendering()
. An alternate approach would just be to remove the ability for custom setters completely. But we do have a few spots that use them.
Also, if we did rename those methods, it should probably be "setFooProp" not "setFooAttr", since these are really properties, not attributes. Or probably better, similar to http://dojotoolkit.org/reference-guide/1.10/dojo/Stateful.html, name them fooGetter()
and fooSetter()
As shown by decor/tests/functional/sniff.html, has("ie")
returns:
IE8: 4
IE9: 5
IE10: 6
IE11: 7
It should return the real IE version, or be renamed to has("trident")
.
Allow custom setters and getters for function (and class) properties too, so a Stateful subclass can have methods like MyWidget#_setTemplateAttr()
(where template
is a function), just like _setNameAttr()
(where name
is a string).
This also means that Invalidating#computeProperties() and Invalidating#refreshRendering() will be notified of changes to function properties.
See related ibm-js/delite#314.
Noticed a few places in deliteful that call notifyCurrentValues() multiple times. So it would be convenient if it could take multiple arguments, like how Destroyable#own() works.
This issue is the follow up of ibm-js/delite#402
@asudoh said:
Guessing @clmath is using node.js 0.8, where setImmediate() is not available. Create a PR adding process.nextTick() support to decor/schedule to cope with that. Also - setImmediate() runs after painting, etc. stuffs happens, whereas end-of-microtask queue like process.nextTick() and Mutation Observer callbacks runs before painting, etc. stuffs - Which means process.nextTick() is much closer to Object.observe() spec than setImmediate() is.
Actually I am using node v0.10.33. I have checked and setImmediate()
is available.
The problem is that the has
plugin is set to not execute feature tests during the build since they could lead to incorrect modules inclusion in the layer.
So has("setImmediate")
is always false during the build even on node v0.10.33.
So maybe a quick fix can be to have a typeof window !== "undefined"
check before accessing window.
It says:
remove()
method to stop listening to event.Windows 10. User agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
Few enhancements for Stateful:
Only make user defined properties enumerable. for (var key in statefulObject)
shouldn't list Stateful's internal methods, the shadow properties, or the custom getter/setter methods.
Declare custom getters/setters using dcl's syntax, i.e.:
dcl(Stateful, {
foo: dcl.prop({
set: function (val) { this._set("foo", val + 1); },
get: function (val) { this._get("foo") - 1; }
enumerable: false
})
})
When using decore/sniff
with:
define(["decor/sniff"], function (has) {
...
}
has("safari")
returns a non falsy value in android stock browser. On the android 4.3 emulator, for example, it returns 4
in the stock browser.
I usually use postscript in dojo to do post creation processing a stateful object. postscript doesn't exist in dcl so it's natural to use constructor. It's strange that Stateful only mix the args in after the constructor chain finished which make the override constructor quite useless. We can either use the args directly or access 'this' in an after advise of the constructor but both approaches are not intuitive.
These methods are marked as private but really, delite/CustomElement overrides them, so they should be considered protected.
Generalize deliver()
and discardChanges()
methods from Invalidating to work in Stateful. The new methods will call deliver()
and discardChanges()
on every listener registered via Stateful#observe()
.
This is somewhat of a prerequisite for ibm-js/delite#389.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.