Skip to content

Commit

Permalink
Merge pull request canjs#868 from bitovi/docco
Browse files Browse the repository at this point in the history
Docco inline documentation
  • Loading branch information
daffl committed Apr 9, 2014
2 parents f2eb8dd + 657fd49 commit fba27ca
Show file tree
Hide file tree
Showing 151 changed files with 5,694 additions and 3,921 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ docs*
*.DS_Store
.idea
bower_components/
test/pluginified/latest.js
test/pluginified/latest.js
docco
25 changes: 16 additions & 9 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,15 +376,22 @@ module.exports = function (grunt) {
}
},
docco: {
dev: {
src: [
'component/**/*.js', 'compute/**/*.js', 'construct/**/*.js', 'control/**/*.js', 'list/**/*.js',
'map/**/*.js', 'model/**/*.js', 'observe/**/*.js','route/**/*.js', 'util/**/*.js','view/**/*.js',
'!util/dojo/dojo-1.8.1.js', '!util/dojo/nodelist-traverse.js','!**/*_test.js'
options: {
dst: 'docco/',
layout : 'parallel',
css : 'resources/docco.css'
},
docs: {
files : [
{
src : [
'component/**/*.js', 'compute/**/*.js', 'construct/**/*.js', 'control/**/*.js', 'list/**/*.js',
'map/**/*.js', 'model/**/*.js', 'observe/**/*.js','route/**/*.js', 'util/**/*.js','view/**/*.js',
'!util/dojo/dojo-1.8.1.js', '!util/dojo/nodelist-traverse.js','!**/*_test.js'
],
expand : true
}
],
options: {
output: 'docco/'
}
}
},
plato: {
Expand Down Expand Up @@ -450,7 +457,7 @@ module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('bitovi-tools');
grunt.loadNpmTasks('grunt-jsbeautifier');
grunt.loadNpmTasks('grunt-docco');
grunt.loadNpmTasks('grunt-docco2');
grunt.loadNpmTasks('grunt-plato');

grunt.registerTask('quality', [ 'jsbeautifier', 'jshint']);
Expand Down
78 changes: 52 additions & 26 deletions component/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,16 @@ steal("can/util", "can/view/callbacks","can/control", "can/observe", "can/view/m
// rebinds all templated event handlers.
can.extend({
setup: function (el, options) {
// call `can.Control.prototype.setup` on the element
var res = can.Control.prototype.setup.call(this, el, options);
// set the scope to the one passed from the `options` object
this.scope = options.scope;
var self = this;
// rebind events on the `scope` change
this.on(this.scope, "change", function updateScope() {
// rebind events
self.on();
// manually rebind this function after this change
self.on(self.scope, "change", updateScope);
});
return res;
Expand Down Expand Up @@ -73,10 +78,13 @@ steal("can/util", "can/view/callbacks","can/control", "can/observe", "can/view/m
if (this.prototype.template) {
if (typeof this.prototype.template === "function") {
var temp = this.prototype.template;
// If `this.prototype.template` is a function create renderer from it by
// wrapping it with the anonymous function that will pass it the arguments
this.renderer = function () {
return can.view.frag(temp.apply(null, arguments));
};
} else {
// otherwise create the render from the string
this.renderer = can.view.mustache(this.prototype.template);
}
}
Expand Down Expand Up @@ -106,15 +114,14 @@ steal("can/util", "can/view/callbacks","can/control", "can/observe", "can/view/m
componentScope,
frag;

// scope prototype properties marked with an "@" are added here
// Add scope prototype properties marked with an "@" to the `initialScopeData` object
can.each(this.constructor.attributeScopeMappings, function (val, prop) {
initalScopeData[prop] = el.getAttribute(can.hyphenate(val));
});

// get the value in the scope for each attribute
// Get the value in the scope for each attribute
// the hookup should probably happen after?
can.each(can.makeArray(el.attributes), function (node, index) {

var name = can.camelize(node.nodeName.toLowerCase()),
value = node.value;
// ignore attributes already in ScopeMappings
Expand All @@ -135,84 +142,94 @@ steal("can/util", "can/view/callbacks","can/control", "can/observe", "can/view/m
componentScope.attr(name, newVal);
scopePropertyUpdating = null;
};
// compute only returned if bindable

// Compute only returned if bindable
compute.bind("change", handler);

// set the value to be added to the scope
// Set the value to be added to the scope
initalScopeData[name] = compute();

// We don't need to listen to the compute `change` if it doesn't have any dependencies
if (!compute.hasDependencies) {
compute.unbind("change", handler);
} else {
// make sure we unbind (there's faster ways of doing this)
// Make sure we unbind (there's faster ways of doing this)
can.bind.call(el, "removed", function () {
compute.unbind("change", handler);
});
// setup two-way binding
// Setup the two-way binding
twoWayBindings[name] = computeData;
}

});

if (this.constructor.Map) {
// If `Map` property is set on the constructor use it to wrap the `initialScopeData`
componentScope = new this.constructor.Map(initalScopeData);
} else if (this.scope instanceof can.Map) {
// If `this.scope` is instance of `can.Map` assign it to the `componentScope`
componentScope = this.scope;
} else if (can.isFunction(this.scope)) {

// If `this.scope` is a function, call the function and
var scopeResult = this.scope(initalScopeData, hookupOptions.scope, el);
// if the function returns a can.Map, use that as the scope

if (scopeResult instanceof can.Map) {
// If the function returns a can.Map, use that as the scope
componentScope = scopeResult;
} else if (scopeResult.prototype instanceof can.Map) {
// If `scopeResult` is of a `can.Map` type, use it to wrap the `initialScopeData`
componentScope = new scopeResult(initalScopeData);
} else {
// Otherwise extend `can.Map` with the `scopeResult` and initialize it with the `initialScopeData`
componentScope = new(can.Map.extend(scopeResult))(initalScopeData);
}

}
// Object to hold the bind handlers so we can tear them down
var handlers = {};
// setup reverse bindings
// Setup reverse bindings
can.each(twoWayBindings, function (computeData, prop) {
handlers[prop] = function (ev, newVal) {
// check that this property is not being changed because
// Check that this property is not being changed because
// it's source value just changed
if (scopePropertyUpdating !== prop) {
computeData.compute(newVal);
}
};
componentScope.bind(prop, handlers[prop]);
});
// teardown reverse bindings when element is removed
// Teardown reverse bindings when the element is removed
can.bind.call(el, "removed", function () {
can.each(handlers, function (handler, prop) {
componentScope.unbind(prop, handlers[prop]);
});
});
// setup attributes bindings
// Setup the attributes bindings
if (!can.isEmptyObject(this.constructor.attributeScopeMappings)) {

// Bind on the `attributes` event and update the scope.
can.bind.call(el, "attributes", function (ev) {
// Convert attribute name from `attribute-name` to the `attributeName` format.
var camelized = can.camelize(ev.attributeName);
if (component.constructor.attributeScopeMappings[camelized]) {
// If there is a mapping for this attribute, update the `componentScope` attribute
componentScope.attr(camelized, el.getAttribute(ev.attributeName));
}
});

}

// Set `componentScope` to `this.scope` and set it to the element's `data` object as a `scope` property
this.scope = componentScope;
can.data(can.$(el), "scope", this.scope);

// create a real Scope object out of the scope property
// Create a real Scope object out of the scope property
var renderedScope = hookupOptions.scope.add(this.scope),

// setup helpers to callback with `this` as the component
options = {
helpers: {}
};


// Setup helpers to callback with `this` as the component
can.each(this.helpers || {}, function (val, prop) {
if (can.isFunction(val)) {
options.helpers[prop] = function () {
Expand All @@ -221,29 +238,30 @@ steal("can/util", "can/view/callbacks","can/control", "can/observe", "can/view/m
}
});

// create a control to listen to events
// Create a control to listen to events
this._control = new this.constructor.Control(el, {
// {ass the scope to the control so we can listen to it's changes
scope: this.scope
});

// if this component has a template (that we've already converted to a renderer)
// If this component has a template (that we've already converted to a renderer)
if (this.constructor.renderer) {
// add content to tags
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
// 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, rendererOptions) {
// first check if there was content within the custom tag
// First check if there was content within the custom tag
// otherwise, render what was within <content>, the default code
var subtemplate = hookupOptions.subtemplate || rendererOptions.subtemplate;

if (subtemplate) {

// rendererOptions.options is a scope of helpers where `<content>` was found, so
// `rendererOptions.options` is a scope 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
// 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;
Expand All @@ -255,37 +273,45 @@ steal("can/util", "can/view/callbacks","can/control", "can/observe", "can/view/m

rendererOptions.options));

// restore the content tag so it could potentially be used again (as in lists)
// Restore the content tag so it could potentially be used again (as in lists)
options.tags.content = contentHookup;
}
};
// render the component's template
// Render the component's template
frag = this.constructor.renderer(renderedScope, hookupOptions.options.add(options));
} else {
// otherwise render the contents between the
// Otherwise render the contents between the
frag = can.view.frag(hookupOptions.subtemplate ? hookupOptions.subtemplate(renderedScope, hookupOptions.options.add(options)) : "");
}
// Append the resulting document fragment to the element
can.appendChild(el, frag);
}
});

// If there is a `$` object and it has the `fn` object then create the `scope` plugin that returns
// the scope object
if (window.$ && $.fn) {
$.fn.scope = function (attr) {
if (attr) {
// If `attr` is passed to the `scope` plugin return the value of that attribute on the `scope` object
return this.data("scope")
.attr(attr);
} else {
// otherwise return the whole scope
return this.data("scope");
}
};
}

// Define the `can.scope` function that can be used to retrieve the `scope` from the element
can.scope = function (el, attr) {
el = can.$(el);
if (attr) {
// If `attr` is passed to the `can.scope` function return the value of that attribute on the `scope` object
return can.data(el, "scope")
.attr(attr);
} else {
// otherwise return the whole scope
return can.data(el, "scope");
}
};
Expand Down
2 changes: 1 addition & 1 deletion component/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@test can/component/test.html
@parent canjs
@release 2.0
@link ../docco/component.html docco
@link ../docco/component/component.html docco


@description Create widgets that use a template, a view-model
Expand Down
Loading

0 comments on commit fba27ca

Please sign in to comment.