Example #1
0
				return oldDomManip.call(this, args, function (elem) {
					var elems;
					if (isFragment(elem)) {
						elems = makeArray( getChildNodes(elem) );
					}
					var ret = callback.apply(this, arguments);
					mutate.inserted(elems ? elems : [elem]);
					return ret;
				});
Example #2
0
function makeTarget(frag, makeRenderer) {
  var path = [];

  var children = getChildNodes(frag);
  for(var i = 0, len = children.length; i < len; i++) {
    walk(children.item(i), path, makeRenderer);
  }

  return viewTarget(path);
}
Example #3
0
	keepsTextNodes =  typeof document !== "undefined" && (function(){
		var testFrag = document.createDocumentFragment();
		var div = document.createElement("div");

		div.appendChild(document.createTextNode(""));
		div.appendChild(document.createTextNode(""));
		testFrag.appendChild(div);

		var cloned  = testFrag.cloneNode(true);

		return childNodes(cloned.firstChild).length === 2;
	})(),
Example #4
0
var renderAndAddToNodeLists = function(newNodeLists, parentNodeList, render, context, args){
	var itemNodeList = [];

	if(parentNodeList) {
		nodeLists.register(itemNodeList,null, parentNodeList, true);
		itemNodeList.parentList = parentNodeList;
		itemNodeList.expression = "#each SUBEXPRESSION";
	}

	var itemHTML = render.apply(context, args.concat([itemNodeList])),
		itemFrag = frag(itemHTML);

	var children = makeArray(childNodes(itemFrag));
	if(parentNodeList) {
		nodeLists.update(itemNodeList, children);
		newNodeLists.push(itemNodeList);
	} else {
		newNodeLists.push(nodeLists.register(children));
	}
	return itemFrag;
},
	proto.connectedCallback = function(){
		// What is the root from which we render?
		var root = this.shadowRoot || this;

		// We only want to render once but connectedCallback gets called
		// any time the element is inserted which could be N number of times.
		if(!this._rendered) {
			// setup our nodeList
			this._nodeList = nodeLists.register([], null, true, false);
			this._nodeList.expression = "<" + this.localName + ">";

			var Element = this.constructor;
			var scope = new Scope(this);
			// var scope = Scope.refsScope().add(this);
			var frag = Element.view(scope, null, this._nodeList);

			// Append the resulting document fragment to the element
			domMutate.appendChild.call(root, frag);
			this._rendered = true;
		}

		// update the nodeList with the new children so the mapping gets applied
		nodeLists.update(this._nodeList, getChildNodes(root));
	};
Example #6
0
			$.fn[name] = function () {
				var elems = [],
					args = makeArray(arguments);

				if (args[0] != null) {
					// documentFragment
					if (typeof args[0] === "string") {
						args[0] = buildFragment(args[0]);
					}
					if (isFragment(args[0])) {
						elems = getChildNodes(args[0]);
					} else if( isArrayLike( args[0] ) ) {
						elems = makeArray(args[0]);
					} else {
						elems = [args[0]];
					}
				}

				var ret = original.apply(this, args);

				mutate.inserted(elems);

				return ret;
			};
Example #7
0
	it("is able to parse html", function(){
		var document = makeDocument();
		document.body.innerHTML = "<div></div><span></span>";
		assert.equal(childNodes(document.body).length, 2, "two children");
	});
Example #8
0
function walk(el, arr, makeRenderer) {
  if(!el) {
    return;
  }

  var node = {};

  switch(el.nodeType) {
    // Element
    case 1:
      var tagName = el.nodeName.toLowerCase();

      if(tagName === "template") {
        bindings.template(el, arr, makeRenderer);
        break;
      }

      node.tag = tagName;
      var isCustomTag = viewCallbacks.tag(node.tag);
      if(isCustomTag) {
        var customAttrs = {};
        addAttributesCallback(node, function(scope, options){
          viewCallbacks.tagHandler(this, node.tag, {
            options: options,
            scope: scope,
            templateType: "my-template",
            setupBindings: bindings.viewModel(customAttrs, scope, options)
          });
        });
      }
      // Bind to attributes
      node.attrs = {};
      var attributes = el.attributes, attr;
      for(var i = 0, len = attributes.length; i < len; i++) {
        attr = attributes.item(i);
        bindings.attribute(attr.name, attr.value, node);
        if(isCustomTag) {
          customAttrs[attr.name] = attr.value;
        }
      }

      arr.push(node);
      break;
    // TextNode
    case 3:
      var value = el.nodeValue;
      var split = bindings.text(value);
      arr.push.apply(arr, split);
      // Break apart this text node
      break;
  }

  var children = getChildNodes(el);

  if(children.length) {
    node.children = [];
  }

  for(var i = 0, len = children.length; i < len; i++) {
    walk(children.item(i), node.children, makeRenderer);
  }
}
Example #9
0
		setup: function(el, componentTagData) {
			var component = this;
			// If a template is not provided, we fall back to
			// dynamic scoping regardless of settings.
			var lexicalContent = (
					(typeof this.leakScope === "undefined" ? true : !this.leakScope) &&
					!!(this.template || this.view)
				);
			// an array of teardown stuff that should happen when the element is removed
			var teardownFunctions = [];
			var initialViewModelData = {};
			var callTeardownFunctions = function() {
					for (var i = 0, len = teardownFunctions.length; i < len; i++) {
						teardownFunctions[i]();
					}
				};
			var setupBindings = !domData.get.call(el, "preventDataBindings");
			var viewModel, frag;

			// ## Scope
			var teardownBindings;
			if (setupBindings) {
				var setupFn = componentTagData.setupBindings ||
					function(el, callback, data){
						return stacheBindings.behaviors.viewModel(el, componentTagData,
																											callback, data);
					};
				teardownBindings = setupFn(el, function(initialViewModelData) {

					var ViewModel = component.constructor.ViewModel,
						viewModelHandler = component.constructor.viewModelHandler,
						viewModelInstance = component.constructor.viewModelInstance;

					if(viewModelHandler) {
						var scopeResult = viewModelHandler.call(component, initialViewModelData, componentTagData.scope, el);
						if (types.isMapLike( scopeResult ) ) {
							// If the function returns a can.Map, use that as the viewModel
							viewModelInstance = scopeResult;
						} else if ( types.isMapLike(scopeResult.prototype) ) {
							// If `scopeResult` is of a `can.Map` type, use it to wrap the `initialViewModelData`
							ViewModel = scopeResult;
						} else {
							// Otherwise extend `can.Map` with the `scopeResult` and initialize it with the `initialViewModelData`
							ViewModel = types.DefaultMap.extend(scopeResult);
						}
					}

					if(ViewModel) {
						viewModelInstance = new component.constructor.ViewModel(initialViewModelData);
					}
					viewModel = viewModelInstance;
					return viewModelInstance;
				}, initialViewModelData);
			}

			// Set `viewModel` to `this.viewModel` and set it to the element's `data` object as a `viewModel` property
			this.viewModel = viewModel;

			domData.set.call(el, "viewModel", viewModel);
			domData.set.call(el, "preventDataBindings", true);

			// Create a real Scope object out of the viewModel property
			// The scope used to render the component's template.
			// However, if there is no template, the "light" dom is rendered with this anyway.
			var shadowScope;
			if (lexicalContent) {
				shadowScope = Scope.refsScope().add(this.viewModel, {
					viewModel: true
				});
			} else {
				// if this component has a template,
				// render the template with it's own Refs scope
				// otherwise, just add this component's viewModel.
				shadowScope = (this.constructor.renderer ?
						componentTagData.scope.add(new Scope.Refs()) :
						componentTagData.scope)
					.add(this.viewModel, {
						viewModel: true
					});
			}
			var options = {
					helpers: {}
				},
				addHelper = function(name, fn) {
					options.helpers[name] = function() {
						return fn.apply(viewModel, arguments);
					};
				};

			// ## Helpers

			// Setup helpers to callback with `this` as the component
			canEach(this.helpers || {}, function(val, prop) {
				if (isFunction(val)) {
					addHelper(prop, val);
				}
			});

			// ## `events` control

			// Create a control to listen to events
			this._control = new this.constructor.Control(el, {
				// Pass the viewModel to the control so we can listen to it's changes from the controller.
				scope: this.viewModel,
				viewModel: this.viewModel,
				destroy: callTeardownFunctions
			});

			// ## Rendering

			// Keep a nodeList so we can kill any directly nested nodeLists within this component
			var nodeList = nodeLists.register([], function() {
				domDispatch.call(el, "beforeremove", [], false);
				if(teardownBindings) {
					teardownBindings();
				}
			}, componentTagData.parentNodeList || true, false);
			nodeList.expression = "<" + this.tag + ">";
			teardownFunctions.push(function() {
				nodeLists.unregister(nodeList);
			});

			// If this component has a template (that we've already converted to a renderer)
			if (this.constructor.renderer) {
				// If `options.tags` doesn't exist set it to an empty object.
				if (!options.tags) {
					options.tags = {};
				}

				// We need be alerted to when a <content> element is rendered so we can put the original contents of the widget in its place
				options.tags.content = function contentHookup(el, contentTagData) {
					// First check if there was content within the custom tag
					// otherwise, render what was within <content>, the default code.
					// `componentTagData.subtemplate` is the content inside this component
					var subtemplate = componentTagData.subtemplate || contentTagData.subtemplate,
						renderingLightContent = subtemplate === componentTagData.subtemplate;

					if (subtemplate) {

						// `contentTagData.options` is a viewModel of helpers where `<content>` was found, so
						// the right helpers should already be available.
						// However, `_tags.content` is going to point to this current content callback.  We need to
						// remove that so it will walk up the chain

						delete options.tags.content;

						// By default, light dom scoping is
						// dynamic. This means that any `{{foo}}`
						// bindings inside the "light dom" content of
						// the component will have access to the
						// internal viewModel. This can be overridden to be
						// lexical with the leakScope option.
						var lightTemplateData;
						if (renderingLightContent) {
							if (lexicalContent) {
								// render with the same scope the component was found within.
								lightTemplateData = componentTagData;
							} else {
								// render with the component's viewModel mixed in, however
								// we still want the outer refs to be used, NOT the component's refs
								// <component> {{some value }} </component>
								// To fix this, we
								// walk down the scope to the component's ref, clone scopes from that point up
								// use that as the new scope.
								lightTemplateData = {
									scope: contentTagData.scope.cloneFromRef(),
									options: contentTagData.options
								};
							}

						} else {
							// we are rendering default content so this content should
							// use the same scope as the <content> tag was found within.
							lightTemplateData = contentTagData;
						}

						if (contentTagData.parentNodeList) {
							var frag = subtemplate(lightTemplateData.scope, lightTemplateData.options, contentTagData.parentNodeList);
							nodeLists.replace([el], frag);
						} else {
							nodeLists.replace([el], subtemplate(lightTemplateData.scope, lightTemplateData.options));
						}

						// Restore the content tag so it could potentially be used again (as in lists)
						options.tags.content = contentHookup;
					}
				};
				// Render the component's template
				frag = this.constructor.renderer(shadowScope, componentTagData.options.add(options), nodeList);
			} else {
				// Otherwise render the contents between the element
				frag = componentTagData.subtemplate ?
					componentTagData.subtemplate(shadowScope, componentTagData.options.add(options), nodeList) :
					document.createDocumentFragment();

			}
			// Append the resulting document fragment to the element
			domMutate.appendChild.call(el, frag);

			// update the nodeList with the new children so the mapping gets applied
			nodeLists.update(nodeList, getChildNodes(el));
		}