diff --git a/build/build_test.js b/build/build_test.js index d74eb58..5e81315 100644 --- a/build/build_test.js +++ b/build/build_test.js @@ -1,4 +1,4 @@ - +require("./make_default_helpers_test"); var getRenderer = require('./get_renderer'), getPartials = require('./get_partials'), diff --git a/build/make_default_helpers.js b/build/make_default_helpers.js index 9c9d70d..494980c 100644 --- a/build/make_default_helpers.js +++ b/build/make_default_helpers.js @@ -267,23 +267,34 @@ module.exports = function(docMap, config, getCurrent, Handlebars){ var replacer = function (match, content) { var parts = content.match(linkRegExp), name, + hashParts, description, linkText, - docObject; + docObject, + href; name = parts ? parts[1].replace('::', '.prototype.') : content; + //the name can be something like 'some-name#someId' + //this allows linking to a specific section with the hash syntax (#27) + hashParts = name.split("#"); + name = hashParts.shift(); + docObject = docMap[name] if (docObject) { linkText = parts && parts[2] ? parts[2] : docObject.title || name; description = docObject.description || name; - return '' + linkText + ''; + //if there is anything in the hashParts, append it to the end of the url + href = urlTo(name) + (hashParts.length >= 1 ? ("#" + hashParts.join("#")) : ""); + + return '' + linkText + ''; } if (httpRegExp.test(name)) { linkText = parts && parts[2] ? parts[2] : name; - return '' + linkText + ''; + href = name; + return '' + linkText + ''; } return match; diff --git a/build/make_default_helpers_test.js b/build/make_default_helpers_test.js new file mode 100644 index 0000000..9eeebab --- /dev/null +++ b/build/make_default_helpers_test.js @@ -0,0 +1,77 @@ +var build = require('./build'), + makeDefaultHelpers = require("./make_default_helpers"), + path = require('path'), + Handlebars = require("handlebars"), + assert = require('assert'), + Q = require('q'); + + +var docMap = { + "can-core": { + "src": { + "path": "docs/can-canjs/can-core.md" + }, + "body": "\n## Use\n\nCanJS’s core libraries are the best, most hardened and generally useful modules. \nEach module is part of an independent package, so you\nshould install the ones you use directly:\n\n```\nnpm install can-define can-set can-connect can-component can-stache can-route --save\n```\n\n\nLet’s explore each module a bit more.\n\n## can-compute\n\n[can-compute]s represent an observable value. A compute can contain its\nown value and notify listeners of changes like:\n\n```js\nvar compute = require(\"can-compute\");\n\nvar name = compute(\"Justin\");\n\n// read the value\nname() //-> \"Justin\"\n\nname.on(\"change\", function(ev, newVal, oldVal){\n\tnewVal //-> \"Matthew\"\n\toldVal //-> \"Justin\"\n});\n\nname(\"Matthew\");\n```\n\nMore commonly, a compute derives its value from other observables. The following\n`info` compute derives its value from a `person` map, `hobbies` list, and `age`\ncompute:\n\n```js\nvar DefineMap = require(\"can-define/map/map\"),\n\tDefineList = require(\"can-define/list/list\"),\n\tcompute = require(\"can-compute\");\n\nvar person = new DefineMap({first: \"Justin\", last: \"Meyer\"}),\n\thobbies = new DefineList([\"js\",\"bball\"]),\n\tage = compute(33);\n\nvar info = compute(function(){\n\treturn person.first +\" \"+ person.last+ \" is \"+age()+\n\t\t\"and like \"+hobbies.join(\", \")+\".\";\n});\n\ninfo() //-> \"Justin Meyer is 33 and likes js, bball.\"\n\ninfo.on(\"change\", function(ev, newVal){\n\tnewVal //-> \"Justin Meyer is 33 and likes js.\"\n});\n\nhobbies.pop();\n```\n\n\n## can-define\n\n[can-define/map/map] and [can-define/list/list] allow you to create observable\nmaps and lists with well defined properties. You can\n[can-define.types.propDefinition define a property’s type initial value, enumerability, getter-setters and much more].\nFor example, you can define the behavior of a `Todo` type and a `TodoList` type as follows:\n\n```js\nvar DefineMap = require(\"can-define/map/map\");\nvar DefineList = require(\"can-define/list/list\");\n\nvar Todo = DefineMap.extend({ // A todo has a:\n name: \"string\", // .name that’s a string\n complete: { // .complete that’s\n\ttype: \"boolean\", // a boolean\n\tvalue: false // initialized to false\n }, \n dueDate: \"date\", // .dueDate that’s a date\n get isPastDue(){ // .pastDue that returns if the\n\treturn new Date() > this.dueDate; // dueDate is before now\n },\n toggleComplete: function(){ // .toggleComplete method that\n this.complete = !this.complete; // changes .complete\n }\n});\n\nvar TodoList = DefineList.extend({ // A list of todos: \n \"#\": Todo, // has numeric properties\n // as todos\n\n get completeCount(){ // has .completeCount that\n return this.filter(\"complete\") // returns # of\n\t .length; // complete todos\n }\n});\n```\n\nThis allows you to create a Todo, read its properties, and\ncall back its methods like:\n\n```js\nvar dishes = new Todo({\n\tname: \"do dishes\",\n\t// due yesterday\n\tdueDate: new Date() - 1000 * 60 * 60 * 24\n});\ndishes.name //-> \"do dishes\"\ndishes.isPastDue //-> true\ndishes.complete //-> false\ndishes.toggleComplete() \ndishes.complete //-> true\n```\n\nAnd it allows you to create a `TodoList`, access its items and properties\nlike:\n\n```js\nvar todos = new TodoList( dishes, {name: \"mow lawn\", dueDate: new Date()});\ntodos.length //-> 2\ntodos[0].complete //-> true\ntodos.completeCount //-> 1\n```\n\nThese observables provide the foundation\nfor data connection (models), view-models and even routing in your application.\n\n## can-set\n\n[can-set] models a service layer’s behavior as a [can-set.Algebra set.Algebra]. Once modeled, other libraries such as [can-connect] or [can-fixture] can\nadd a host of functionality like: real-time behavior, performance optimizations, and\nsimulated service layers.\n\nA `todosAlgebra` set algebra for a `GET /api/todos` service might look like:\n\n```js\nvar set = require(\"can-set\");\nvar todosAlgebra = new set.Algebra(\n // specify the unique identifier property on data\n set.prop.id(\"_id\"), \n // specify that completed can be true, false or undefined\n set.prop.boolean(\"complete\"),\n // specify the property that controls sorting\n set.prop.sort(\"orderBy\")\n)\n```\n\nThis assumes that the service:\n\n - Returns data where the unique property name is `_id`:\n ```js\n GET /api/todos\n -> [{_id: 1, name: \"mow lawn\", complete: true},\n {_id: 2, name: \"do dishes\", complete: false}, ...]\n ```\n - Can filter by a `complete` property:\n ```js\n GET /api/todos?complete=false\n -> [{_id: 2, name: \"do dishes\", complete: false}, ...]\n ```\n - Sorts by an `orderBy` property:\n ```js\n GET /api/todos?orderBy=name\n -> [{_id: 2, name: \"do dishes\", complete: false},\n {_id: 1, name: \"mow lawn\", complete: true}]\n ```\n\nIn the next section will use `todoAlgebra` to build a model with [can-connect].\n\n## can-connect\n\n[can-connect] connects a data type, typically a `DefineMap` and its `DefineList`,\nto a service layer. This is often done via the\n[can-connect/can/base-map/base-map] module which bundles many common behaviors\ninto a single api:\n\n```js\nvar baseMap = require(\"can-connect/can/base-map/base-map\"),\n DefineMap = require(\"can-define/map/map\"),\n DefineList = require(\"can-define/list/list\"),\n\tset = require(\"can-set\");\n\nvar Todo = DefineMap.extend({\n\t...\n});\nvar TodosList = DefineMap.extend({\n\t\"#\": Todo,\n\t...\n});\nvar todosAlgebra = new set.Algebra({\n\t...\n});\n\nvar connection = baseMap({\n\turl: \"/api/todos\",\n\tMap: Todo,\n\tList: TodoList,\n\talgebra: todosAlgebra,\n\tname: \"todo\"\n});\n```\n\n`baseMap` extends the `Map` type, in this case, `Todo`, with\nthe ability to make requests to the service layer.\n\n - [can-connect/can/map/map.getList Get a list] of Todos\n ```js\n Todo.getList({complete: true}).then(function(todos){})\n ```\n - [can-connect/can/map/map.get Get] a single Todo\n ```js\n Todo.get({_id: 6}).then(function(todo){})\n ```\n - [can-connect/can/map/map.prototype.save Create] a Todo\n ```js\n var todo = new Todo({name: \"do dishes\", complete: false})\n todo.save().then(function(todo){})\n ```\n - [can-connect/can/map/map.prototype.save Update] an [can-connect/can/map/map.prototype.isNew already created] Todo\n ```js\n todo.complete = true;\n todo.save().then(function(todo){})\n ```\n - [can-connect/can/map/map.prototype.destroy Delete] a Todo\n ```js\n todo.destroy().then(function(todo){})\n ```\n\n[can-connect] is also middleware, so custom connections can\nbe assembled too:\n\n```js\nvar base = require(\"can-connect/base/base\");\nvar dataUrl = require(\"can-connect/data-url/data-url\");\nvar constructor = require(\"can-connect/constructor/constructor\");\nvar map = require(\"can-connect/can/map/map\");\n\nvar options = {\n\turl: \"/api/todos\",\n\tMap: Todo,\n\tList: TodoList,\n\talgebra: todosAlgebra,\n\tname: \"todo\"\n}\nvar connection = map(constructor(dataUrl(base(options))));\n```\n\n## can-stache\n\n[can-stache] provides live binding mustache and handlebars syntax. While\ntemplates should typically be loaded with a module loader like [steal-stache],\nyou can create a template programmatically that lists out todos within a\npromise loaded from `Todo.getList` like:\n\n```js\nvar stache = require(\"can-stache\");\n\n// Creates a template\nvar template = stache(\n\t\"