Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DON'T MERGE: point at can-observation-recorder #65

Merged
merged 52 commits into from
Jan 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
79be61c
switching to observation recorder
justinbmeyer Oct 8, 2017
b5a2bcb
no package-lock
justinbmeyer Oct 8, 2017
020267d
4.0.0-pre.1
justinbmeyer Oct 8, 2017
d9416aa
don't ignore test folder
justinbmeyer Oct 27, 2017
e8c80dd
4.0.0-pre.2
justinbmeyer Oct 27, 2017
2c8d940
Merge branch 'master' into merge-master-to-major
chasenlehara Nov 10, 2017
4976964
Merge pull request #67 from canjs/merge-master-to-major
imaustink Nov 10, 2017
48c9e65
4.0.0-pre.3
chasenlehara Nov 10, 2017
c021015
reading local tags from templateContext instead of optionsScope
phillipskevin Nov 27, 2017
e5d4f84
4.0.0-pre.4
phillipskevin Nov 27, 2017
85c2fc5
Merge branch 'master' into major
chasenlehara Dec 13, 2017
ddfdb06
4.0.0-pre.5
chasenlehara Dec 13, 2017
226bb60
Merge branch 'master' into major
chasenlehara Dec 21, 2017
70e0ea2
4.0.0-pre.6
chasenlehara Dec 21, 2017
09233f6
Merge branch 'master' into major
chasenlehara Dec 27, 2017
be884e6
Update the docs to match the demos
chasenlehara Dec 27, 2017
0fd7be0
4.0.0-pre.7
chasenlehara Dec 27, 2017
cbdd6db
Use can-globals and can-dom-mutate
andrejewski Dec 19, 2017
2a67c83
Merge pull request #71 from canjs/magneto
andrejewski Dec 29, 2017
1ba5fb4
4.0.0-pre.8
andrejewski Dec 29, 2017
1fe536d
Change can-observation-recorder semver range to <2.0.0
chasenlehara Dec 29, 2017
dc14a8c
4.0.0-pre.9
chasenlehara Dec 29, 2017
1d7b59e
Pass nodeList through when there is a subtemplate and the tag returns.
matthewp Jan 3, 2018
bfdc566
Merge pull request #73 from canjs/nl
matthewp Jan 3, 2018
ffe726e
4.0.0-pre.10
matthewp Jan 3, 2018
f5c86e5
updating tests to use can-test-helpers
phillipskevin Jan 11, 2018
5b963cb
Merge pull request #76 from canjs/test-helpers
phillipskevin Jan 12, 2018
95da544
automatically calling tagHandler for tags in the document
phillipskevin Jan 12, 2018
58fe035
not caching GLOBAL
phillipskevin Jan 12, 2018
2cf01f1
calling tagHandler adds item to Set that will prevent re-rendering
phillipskevin Jan 12, 2018
549974e
not calling customElements.define if tagName is illegal
phillipskevin Jan 12, 2018
a9f1514
Merge pull request #77 from canjs/automatic-mounting
phillipskevin Jan 12, 2018
fdb924a
4.0.0-pre.11
phillipskevin Jan 12, 2018
07ec83d
unbreaking tags without hyphens in the tagName
phillipskevin Jan 12, 2018
f7b9c02
4.0.0-pre.12
phillipskevin Jan 12, 2018
6cabf03
fixing issue with registering the same tag twice
phillipskevin Jan 13, 2018
d7323c7
4.0.0-pre.13
phillipskevin Jan 13, 2018
bf6979f
preventing customElements.define from being called twice for the same…
phillipskevin Jan 16, 2018
a889f09
4.0.0-pre.14
phillipskevin Jan 16, 2018
ff784a5
Prevent MutationObserver code from throwing in env without MO
matthewp Jan 16, 2018
4946a1e
Set back the MO/ce after its test
matthewp Jan 16, 2018
13d2593
Merge pull request #79 from canjs/MO
matthewp Jan 16, 2018
9dd0163
When resetting the globals, pass a function
matthewp Jan 16, 2018
e25deb1
4.0.0-pre.15
matthewp Jan 16, 2018
0775491
Only automount if the can-automount flag is not set to false
matthewp Jan 17, 2018
a02681b
Disconnect the mutationobserver when automount is disabled
matthewp Jan 17, 2018
a89a757
Merge pull request #80 from canjs/automount-false
matthewp Jan 17, 2018
21020bc
4.0.0-pre.16
matthewp Jan 17, 2018
378bb54
correcting the arguments passed to tagHandlers by MutationObserver / …
phillipskevin Jan 17, 2018
57a005d
4.0.0-pre.17
phillipskevin Jan 17, 2018
1966131
Merge branch 'master' into major
chasenlehara Jan 26, 2018
548edb0
getting ready for 4.0.0
justinbmeyer Jan 27, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
"start": true,
"stop": true,
"global": true,
"Promise": true
"Promise": true,
"customElements": true,
"Reflect": true,
"WeakSet": true
},
"strict": false,
"curly": true,
Expand Down
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
!dist/
!dist/
!test/
159 changes: 142 additions & 17 deletions can-view-callbacks.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,91 @@
var Observation = require('can-observation');
var ObservationRecorder = require('can-observation-recorder');

var dev = require('can-util/js/dev/dev');
var getGlobal = require('can-util/js/global/global');
var domMutate = require('can-util/dom/mutate/mutate');
var dev = require('can-log/dev/dev');
var getGlobal = require('can-globals/global/global');
var domMutate = require('can-dom-mutate/node');
var namespace = require('can-namespace');
var nodeLists = require('can-view-nodelist');
var makeFrag = require("can-util/dom/frag/frag");
var globals = require('can-globals');

//!steal-remove-start
var requestedAttributes = {};
//!steal-remove-end

var tags = {};

// WeakSet containing elements that have been rendered already
// and therefore do not need to be rendered again

var automountEnabled = function(){
return globals.getKeyValue("document").documentElement.getAttribute("data-can-automount") !== "false";
};

var renderedElements = new WeakSet();

var renderNodeAndChildren = function(node) {
var tagName = node.tagName && node.tagName.toLowerCase();
var tagHandler = tags[tagName];
var children;

// skip elements that already have a viewmodel or elements whose tags don't match a registered tag
// or elements that have already been rendered
if (tagHandler && !renderedElements.has(node)) {
tagHandler(node, {});
}

if (node.getElementsByTagName) {
children = node.getElementsByTagName("*");
for (var k=0, child; (child = children[k]) !== undefined; k++) {
renderNodeAndChildren(child);
}
}
};

var mutationObserverEnabled = false;
var globalMutationObserver;
var enableMutationObserver = function() {
if (mutationObserverEnabled) {
return;
}

var mutationHandler = function(mutationsList) {
var addedNodes;

for (var i=0, mutation; (mutation = mutationsList[i]) !== undefined; i++) {
if (mutation.type === "childList") {
addedNodes = mutation.addedNodes;

for (var j=0, addedNode; (addedNode = addedNodes[j]) !== undefined; j++) {
// skip elements that have already been rendered
if (!renderedElements.has(addedNode)) {
renderNodeAndChildren(addedNode);
}
}
}
}
};

var MutationObserver = globals.getKeyValue("MutationObserver");
if(MutationObserver) {
globalMutationObserver = new MutationObserver(mutationHandler);
globalMutationObserver.observe(getGlobal().document.documentElement, {
childList: true,
subtree: true
});

mutationObserverEnabled = true;
}
};

var renderTagsInDocument = function(tagName) {
var nodes = getGlobal().document.getElementsByTagName(tagName);

for (var i=0, node; (node = nodes[i]) !== undefined; i++) {
renderNodeAndChildren(node);
}
};

var attr = function (attributeName, attrHandler) {
if(attrHandler) {
if (typeof attributeName === "string") {
Expand Down Expand Up @@ -46,7 +123,7 @@ var attr = function (attributeName, attrHandler) {
//!steal-remove-start
requestedAttributes[attributeName] = true;
//!steal-remove-end

return cb;
}
};
Expand All @@ -60,21 +137,64 @@ var tag = function (tagName, tagHandler) {
if(tagHandler) {
var GLOBAL = getGlobal();

var validCustomElementName = automaticCustomElementCharacters.test(tagName),
tagExists = typeof tags[tagName.toLowerCase()] !== 'undefined',
customElementExists;

//!steal-remove-start
if (typeof tags[tagName.toLowerCase()] !== 'undefined') {
if (tagExists) {
dev.warn("Custom tag: " + tagName.toLowerCase() + " is already defined");
}
if (!automaticCustomElementCharacters.test(tagName) && tagName !== "content") {

if (!validCustomElementName && tagName !== "content") {
dev.warn("Custom tag: " + tagName.toLowerCase() + " hyphen missed");
}
//!steal-remove-end

// if we have html5shiv ... re-generate
if (GLOBAL.html5) {
GLOBAL.html5.elements += " " + tagName;
GLOBAL.html5.shivDocument();
}

tags[tagName.toLowerCase()] = tagHandler;

if(automountEnabled()) {
var customElements = globals.getKeyValue("customElements");

// automatically render elements that have tagHandlers
// If browser supports customElements, register the tag as a custom element
if (customElements) {
customElementExists = customElements.get(tagName.toLowerCase());

if (validCustomElementName && !customElementExists) {
var CustomElement = function() {
return Reflect.construct(HTMLElement, [], CustomElement);
};

CustomElement.prototype.connectedCallback = function() {
// don't re-render an element that has been rendered already
if (!renderedElements.has(this)) {
tags[tagName.toLowerCase()](this, {});
}
};

Object.setPrototypeOf(CustomElement.prototype, HTMLElement.prototype);
Object.setPrototypeOf(CustomElement, HTMLElement);

customElements.define(tagName, CustomElement);
}
}
// If browser doesn't support customElements, set up MutationObserver for
// rendering elements when they are inserted in the page
// and rendering elements that are already in the page
else {
enableMutationObserver();
renderTagsInDocument(tagName);
}
} else if(mutationObserverEnabled) {
globalMutationObserver.disconnect();
}
} else {
var cb;

Expand All @@ -93,7 +213,6 @@ var tag = function (tagName, tagHandler) {
}

};
var tags = {};

var callbacks = {
_tags: tags,
Expand All @@ -104,15 +223,18 @@ var callbacks = {
attr: attr,
// handles calling back a tag callback
tagHandler: function(el, tagName, tagData){
var helperTagCallback = tagData.options.get('tags.' + tagName,{proxyMethods: false}),
tagCallback = helperTagCallback || tags[tagName];

// If this was an element like <foo-bar> that doesn't have a component, just render its content
var scope = tagData.scope,
helperTagCallback = scope && scope.templateContext.tags.get(tagName),
tagCallback = helperTagCallback || tags[tagName],
res;

// If this was an element like <foo-bar> that doesn't have a component, just render its content
if(tagCallback) {
res = Observation.ignore(tagCallback)(el, tagData);
res = ObservationRecorder.ignore(tagCallback)(el, tagData);

// add the element to the Set of elements that have had their handlers called
// this will prevent the handler from being called again when the element is inserted
renderedElements.add(el);
} else {
res = scope;
}
Expand All @@ -123,20 +245,23 @@ var callbacks = {
var ceConstructor = GLOBAL.document.createElement(tagName).constructor;
// If not registered as a custom element, the browser will use default constructors
if (ceConstructor === GLOBAL.HTMLElement || ceConstructor === GLOBAL.HTMLUnknownElement) {
dev.warn('can-view-callbacks: No custom element found for ' + tagName);
dev.warn('can-view-callbacks: No custom element found for ' + tagName);
}
}
//!steal-remove-end

// If the tagCallback gave us something to render with, and there is content within that element
// render it!
if (res && tagData.subtemplate) {

if (scope !== res) {
scope = scope.add(res);
}
var result = tagData.subtemplate(scope, tagData.options);
var frag = typeof result === "string" ? can.view.frag(result) : result;

var nodeList = nodeLists.register([], undefined, tagData.parentNodeList || true, false);
nodeList.expression = "<" + el.tagName + ">";

var result = tagData.subtemplate(scope, tagData.options, nodeList);
var frag = typeof result === "string" ? makeFrag(result) : result;
domMutate.appendChild.call(el, frag);
}
}
Expand Down
46 changes: 23 additions & 23 deletions docs/attr.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Handlers must be registered before templates using them are parsed.

```js
var canViewCallbacks = require("can-view-callbacks");
var domEvents = require("can-util/dom/events/events");

canViewCallbacks.attr("show-when", function(el, attrData){
var prop = el.getAttribute("show-when");
Expand Down Expand Up @@ -150,47 +151,46 @@ var showing = attrData.scope.compute("showing")
This value can be written to by `toggle`:

```js
canViewCallbacks.attr("toggle", function(el, attrData){
canViewCallbacks.attr("toggle", function(el, attrData) {
var attrValue = el.getAttribute("toggle");
var toggleCompute = attrData.scope.compute(attrValue);

var attrValue = el.getAttribute("toggle")
toggleCompute = attrData.scope.compute(attrValue);

$(el).click(function(){
toggleCompute(! toggleCompute() )
})

})
$(el).click(function() {
toggleCompute( ! toggleCompute() );
});
});
```

Or listened to by `fade-in-when`:

```js
canViewCallbacks.attr("fade-in-when", function( el, attrData ) {
canViewCallbacks.attr("fade-in-when", function(el, attrData) {
var attrValue = el.getAttribute("fade-in-when");
fadeInCompute = attrData.scope.compute(attrValue),
// handler for when the compute changes
handler = function(ev, newVal, oldVal){
if(newVal && !oldVal) {
$(el).fadeIn("slow")
} else if(!newVal){
$(el).hide()
}
var fadeInCompute = attrData.scope.compute(attrValue);

// handler for when the observable changes
var handler = function(event, newVal, oldVal) {
if (newVal && !oldVal) {
$(el).fadeIn("slow")
} else if (!newVal) {
$(el).hide()
}
};

fadeInCompute.on("change",handler);
fadeInCompute.on("change", handler);

...

})
});
```

When you listen to something other than the attribute’s element, remember to
unbind the event handler when the element is [can-util/dom/events/removed/removed removed] from the page:

```js
domEvents.addEventListener.call(el,"removed", function(){
fadeInCompute.off(handler);
});
domEvents.addEventListener.call(el, "removed", function() {
fadeInCompute.off("change", handler);
});
```

@demo demos/can-view-callbacks/fade_in_when.html
Expand Down
24 changes: 11 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "can-view-callbacks",
"version": "3.2.5",
"version": "4.0.0-pre.17",
"description": "Registered callbacks for behaviors",
"homepage": "http://canjs.com",
"homepage": "https://canjs.com/doc/can-view-callbacks.html",
"repository": {
"type": "git",
"url": "git://github.com/canjs/can-view-callbacks.git"
Expand All @@ -13,9 +13,8 @@
"url": "http://bitovi.com"
},
"scripts": {
"preversion": "npm test && npm run build",
"version": "git commit -am \"Update dist for release\" && git checkout -b release && git add -f dist/",
"postversion": "git push --tags && git checkout master && git branch -D release && git push",
"preversion": "npm test",
"postpublish": "git push --tags && git push",
"testee": "testee test/test.html --browsers firefox",
"test": "npm run detect-cycle && npm run jshint && npm run testee",
"jshint": "jshint ./*.js --config",
Expand All @@ -24,7 +23,6 @@
"release:minor": "npm version minor && npm publish",
"release:major": "npm version major && npm publish",
"build": "node build.js",
"develop": "done-serve --static --develop --port 8080",
"detect-cycle": "detect-cyclic-packages --ignore done-serve"
},
"main": "can-view-callbacks",
Expand All @@ -33,18 +31,18 @@
"canjs-plugin",
"donejs"
],
"steal": {
"configDependencies": [
"live-reload"
]
},
"dependencies": {
"can-dom-mutate": "^1.0.0",
"can-globals": "^1.0.0",
"can-log": "^1.0.0",
"can-namespace": "1.0.0",
"can-observation": "^3.3.1",
"can-util": "^3.9.5"
"can-observation-recorder": "^1.0.0",
"can-util": "^3.9.5",
"can-view-nodelist": "^4.0.0"
},
"devDependencies": {
"can-test-helpers": "^1.0.1",
"can-view-scope": "^4.0.0-pre.34",
"detect-cyclic-packages": "^1.1.0",
"done-serve": "^1.2.0",
"jshint": "^2.9.1",
Expand Down
Loading