GithubHelp home page GithubHelp logo

ibm-js / decor Goto Github PK

View Code? Open in Web Editor NEW
5.0 5.0 14.0 660 KB

Utility classes and functions used by ibm-js. Non-widget, non-UI related functionality.

License: Other

JavaScript 98.98% HTML 1.02%

decor's People

Contributors

asudoh avatar cjolif avatar clmath avatar dependabot[bot] avatar harbalk avatar wkeese avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

decor's Issues

Invalidating on Chrome 36: refreshRendering should not be called on private attribute change

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

decor/observe gets stack overflow when properties point to HTMLElements

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");

Remove binding in Stateful#observe() and Destroyable#own()

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`,

observe() and bind() modules

Create observe() and bind() modules for programatic binding from POJOs to Stateful subclasses.

observe()

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:

  1. instruments existing objects rather than creating new ones
  2. (similar to Stateful) tracks direct updates to object properties rather than requiring a set() method
  3. tracks nested updates

observe() will (at least initially) report changed properties in an oldValues hash, same as decor/Stateful.

bind()

bind() is similar in functionality to liaison's ObservablePath, with the difference that it works on POJOs.

call Stateful#deliver() automatically on widget creation?

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

has("object-is-api") always false, Object.is() never used

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.

update dependencies in README

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?

Return of Observable.observe.remove()

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

decor/sniff (and delite/uacss) broken on iOS 13.1+

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() issue on objects with both destroy() and remove() methods

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.)

`bower install decor` doesn't work

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

Stateful: notify on changes to underscore props?

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.

Invalidating: chain computeProperties() and refreshRendering()

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().

Protected members should not start with "_"

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 _setand _get members. However, not sure if just removing the underscore prefix would be a safe way to go (potential risk of clash?).

decor/sniff: platform detection should be uncoupled from "webkit" detection

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.

remove has("mozilla") flag

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).

Stateful: rename _set(), _get(), _setFooAttr() etc. to remove underscores?

Our rule is that only private methods/properties should have underscores. Therefore _set(), _get(), _setFooAttr() etc. probably shouldn't have underscores.

set() and get()

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.

About _setFooAttr

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()

has("ie") returns strange number

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").

Stateful: call custom setters/getters for function properties too

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.

make notifyCurrentValues() take var_args

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.

decor/schedule should be loadable during the build.

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.

add has("edge") flag for Edge

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"

Stateful: enhance and align API with dcl v2

Few enhancements for Stateful:

  1. 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.

  2. 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
   })
})

Stateful: constructor args should be mixed in before sub-class' constructor called

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.