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

Documentation Tweeks #380

Merged
merged 8 commits into from
Aug 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 10 additions & 2 deletions can-define.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ function eachPropertyDescriptor(map, cb){
}
}

function getEveryPropertyAndSymbol(obj) {
var props = Object.getOwnPropertyNames(obj);
var symbols = ("getOwnPropertySymbols" in Object) ?
Object.getOwnPropertySymbols(obj) : [];
return props.concat(symbols);
}

function cleanUpDefinition(prop, definition, shouldWarn, typePrototype){
// cleanup `value` -> `default`
if(definition.value !== undefined && ( typeof definition.value !== "function" || definition.value.length === 0) ){
Expand Down Expand Up @@ -170,14 +177,15 @@ module.exports = define = ns.define = function(typePrototype, defines, baseDefin
}

// Add necessary event methods to this object.
for (prop in eventsProto) {
getEveryPropertyAndSymbol(eventsProto).forEach(function(prop){
Object.defineProperty(typePrototype, prop, {
enumerable: false,
value: eventsProto[prop],
configurable: true,
writable: true
});
}
});
// also add any symbols
// add so instance defs can be dynamically added
Object.defineProperty(typePrototype,"_define",{
enumerable: false,
Expand Down
100 changes: 73 additions & 27 deletions docs/define.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,77 @@
@module {function} can-define
@parent can-observables
@collection can-core
@description Exports the `define` method that defines observable properties
and their behavior on a prototype object.
@description Defines observable properties and their behavior on a prototype object. This
function is not commonly used directly. [can-define/map/map]
and [can-define/list/list] are more commonly used. Types and
behaviors shared by both [can-define/map/map]
and [can-define/list/list] are documented here.
@group can-define.static 0 static
@group can-define.typedefs 1 types
@group can-define.behaviors 2 behaviors
@package ../package.json
@templateRender true

@signature `define(prototype, propDefinitions)`

Define observable properties, type conversion, and getter/setter logic on [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain prototype objects].
The `define` function can be used to define observable properties, type conversion, and getter/setter logic on [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain prototype objects]. The `define` function is used by [can-define/map/map] and [can-define/list/list] to
create observables. However, `define` can be used to create observables from types that
do not inherit from [can-define/map/map] and [can-define/list/list].

```js
import define from "can-define";
For more information on observables and how they are used in CanJS, please read
the [guides/technology-overview].

const Greeting = function( message ) {
this.message = message;
};
The following creates a `Greeting` type which will have observable `message`
properties:

define( Greeting.prototype, {
message: { type: "string" }
} );
```
```js
import {define, Reflect as canReflect} from "can";

const Greeting = function( message ) {
this.message = message;
};

define( Greeting.prototype, {
message: { type: "string" }
} );

var greeting = new Greeting("Hello");

canReflect.onKeyValue(greeting, "message", (newValue) => {
console.log(newValue); // logs "goodbye"
});

greeting.message = "goodbye";
```
@codepen

@param {Object} prototype The prototype object of a constructor function or [class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class). The prototype
object will have getter/setters defined on it that carry out the defined behavior. The prototype will also contain
all of [can-event-queue/map/map]'s methods.

@param {Object<String,can-define.types.propDefinition>} propDefinitions An object of
properties and their definitions.
properties and their definitions. For example, a property (`propertyName`) has a [can-define.types.propDefinition] object with zero or more of the following behaviors:

```js
define(Type.prototype, {
propertyName: {
default: function() { /* ... */ },
Default: Constructor,
type: function() { /* ... */ },
Type: Constructor,
get: function() { /* ... */ },
value: function() { /* ... */ },
set: function() { /* ... */ },
serialize: function() { /* ... */ },
identity: Boolean
}
})
```

@body

@body


## Use

`can-define` provides a way to create custom types with observable properties.
Expand All @@ -45,11 +81,13 @@ to create completely customized types.


The following creates a
`Person` constructor function:
`Person` constructor function that
will be used to create `Person` instances with observable properties:

```js
import define from "can-define";
import {define} from "can";

// Define the type
const Person = function( first, last ) {
this.first = first;
this.last = last;
Expand All @@ -63,23 +101,31 @@ define( Person.prototype, {
}
}
} );
```

This can be used to create `Person` instances with observable properties:

```js
// Create an instance
const person = new Person( "Justin", "Meyer" );
person.first; //-> "Justin"
person.last; //-> "Meyer"
person.fullName; //-> "Justin Meyer"

console.log( person.first ) //-> "Justin"
console.log( person.last ) //-> "Meyer"
console.log( person.fullName ) //-> "Justin Meyer"

person.on( "fullName", function( ev, newVal, oldVal ) {
newVal; //-> "Ramiya Meyer"
oldVal; //-> "Justin Meyer"
console.log( newVal ) //-> "Ramiya Meyer"
console.log( oldVal ) //-> "Justin Meyer"
} );

person.first = "Ramiya";
```
@codepen

The observable properties call [can-observation-recorder.add ObservationRecorder.add] so they can be automatically by
[can-observation] (and therefore [can-stache]).


## Mixed-in instance methods and properties

`define` adds the following methods from
[can-event-queue/map/map]:

The observable properties call [can-observation-recorder.add ObservationRecorder.add] so they can be observed by
[can-compute].
{{#each (getChildren [can-event-queue/map/map])}}
- [{{name}}] - {{description}}{{/each}}
92 changes: 61 additions & 31 deletions docs/define.types.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
@property {Object} can-define.types types
@parent can-define.static
Defines the type, initial value, and get, set, and serialize behavior for an
observable property. All type converters leave `null` and `undefined` as is except for

Specify a type to convert values to. Type coercion only applies when setting a property.
All types leave `null` and `undefined` as is except for
the `"htmlbool"` type converter.

@option {function} observable The default type behavior. It converts plain Objects to
[can-define/map/map DefineMaps] and plain Arrays to [can-define/list/list DefineLists]. Everything else is left as is.
@option {function} any Leaves the set value as is, performs no type conversion. Aliased as `*`.
@option {function} string Converts to a string with `""+val`.
@option {function} date Converts to a JavaScript date using `Date.parse(val)` if a string is given or `new Date(val)` if a number is passed.
@option {function} number Converts to a number with `+(val)`.
@option {function} boolean Converts to `false` if `val` is falsey, `"0"`, or `"false"`; otherwise, converts to `true`.
@option {function} htmlbool Like `boolean`, but converts to `true` if empty string (`""`) is passed.
@option {function} compute Allows computes to be passed and the property take on the value of the compute.
@option {function} stringOrObservable Converts plain Objects to [can-define/map/map DefineMaps], plain Arrays to [can-define/list/list DefineLists] and everything else to strings. This is useful for routing.
@type {Object}

All of the following type names can be used as part of a [can-define.types.type] property
behavior like:

```js
DefineMap.extend({
age: {type: "number"}
});
```

Or they can be used in the [can-define.types.propDefinition#String type property definition shorthand]:

```js
DefineMap.extend({
age: "number"
});
```

@option {function} observable The default type behavior. It converts plain Objects to
[can-define/map/map DefineMaps] and plain Arrays to [can-define/list/list DefineLists]. Everything else is left as is.
@option {function} any Leaves the set value as is, performs no type conversion. Aliased as `*`.
@option {function} string Converts to a string with `""+val`. This is the equivalent to [can-data-types/maybe-string/maybe-string MaybeString].
@option {function} date Converts to a JavaScript date using `Date.parse(val)` if a string is given or `new Date(val)` if a number is passed. This is the equivalent to [can-data-types/maybe-date/maybe-date MaybeDate].
@option {function} number Converts to a number with `+(val)`. This is the equivalent to [can-data-types/maybe-number/maybe-number MaybeNumber].
@option {function} boolean Converts to `false` if `val` is falsey, `"0"`, or `"false"`; otherwise, converts to `true`. This is the equivalent to [can-data-types/maybe-boolean/maybe-boolean MaybeBoolean].
@option {function} htmlbool Like `boolean`, but converts to `true` if empty string (`""`) is passed.
@option {function} compute Allows computes to be passed and the property take on the value of the compute.
@option {function} stringOrObservable Converts plain Objects to [can-define/map/map DefineMaps], plain Arrays to [can-define/list/list DefineLists] and everything else to strings. This is useful for routing.

@body

Expand All @@ -22,36 +42,46 @@ the `"htmlbool"` type converter.
Use any of the type names on a [can-define.types.propDefinition]'s `type` or directly on the prototype of a [can-define/map/map DefineMap] or [can-define/map/map DefineList].

```js
import define from "can-define";
import DefineMap from "can-define/map/map";

const Animal = function( name ) {
this.name = name;
};
define( Animal.prototype, {
name: { type: "string" }
} );
import {DefineMap} from "can";

const Person = DefineMap.extend( {
name: "string"
age: "number"
} );

var person = new Person({age: "30"});

console.log(person.age) //-> 30
```
@codepen

You can also pass these functions in directly:


```js
import define from "can-define";
import DefineMap from "can-define/map/map";

const Animal = function( name ) {
this.name = name;
};
define( Animal.prototype, {
name: { type: define.type.string }
import {DefineMap, define} from "can";

const Person = DefineMap.extend( {
age: define.types.number
} );

var person = new Person({age: "30"});

console.log(person.age) //-> 30
```
@codepen


And you can use the [can-data-types] types too:

```js
import {DefineMap, MaybeNumber} from "can";

const Person = DefineMap.extend( {
name: define.type.string
age: MaybeNumber
} );

var person = new Person({age: "30"});

console.log(person.age) //-> 30
```
@codepen
32 changes: 16 additions & 16 deletions docs/types.propDefinition.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ observable property. These behaviors can be specified with as an `Object`, `Str
@option {can-define.types.default} default Specifies the initial value of the property or a function that returns the initial value.

```js
import { DefineMap } from "can";

// A default age of `0`:
const Person = DefineMap.extend( {
age: {
default: 0
},
address: {
default: function() {
return { city: "Chicago", state: "IL" };
import { DefineMap } from "can";

// A default age of `0`:
const Person = DefineMap.extend( {
age: {
default: 0
},
address: {
default: function() {
return { city: "Chicago", state: "IL" };
}
}
}
} );

const person = new Person();
console.log(person.age); //-> 0
```
} );

const person = new Person();
console.log(person.age); //-> 0
```

@option {can-define.types.defaultConstructor} Default Specifies a function that will be called with `new` whose result is set as the initial value of the attribute.

Expand Down
34 changes: 26 additions & 8 deletions list/docs/prototype.assign.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
@function can-define/list/list.prototype.assign assign
@parent can-define/list/list.prototype

Sets items or properties on a list.
Sets values within a list or properties on a list.

@signature `list.assign(newProps)`
@signature `list.assign(newItems)`

Assigns the properties on the list with `newProps`. Properties not present in `newProps` will be left unchanged.
If `newItems` [can-reflect.isListLike is list like] the values in `newItems` will replace the indexed value in the `list`. For example:

```js
import { DefineList } from "can";
const list = new DefineList(["A","B"]);
list.assign({count: 1000, skip: 2});
console.log(list.get("count")); //-> 1000
import { DefineList } from "can";

const list = new DefineList(["A","B"]);

list.assign( ["a"] );
console.log( list.serialize() ); //-> ["a","B"]
```
@codepen

> NOTICE: `.assign()` will not remove properties in the list that have indexes
greater than or equal to the `newItem`'s length. Use [can-define/list/list.prototype.update .update()] to replace all of a list's values.

If `newItems` is an object, the object's properties will be added as properties to
the `list`. For example:

```js
import { DefineList } from "can";

const list = new DefineList(["A","B"]);

list.assign( {count: 1000, skip: 2} );
console.log( list.count ); //-> 1000
```
@codepen

@param {Array} newProps Properties that need to be assigned to the list instance
@param {Array|Object} newItems A list or array of values, or an object of properties.
@return {can-define/list/list} The list instance.
Loading