Skip to content

Commit

Permalink
Merge faee9d5 into f2212fe
Browse files Browse the repository at this point in the history
  • Loading branch information
flongo committed Oct 2, 2014
2 parents f2212fe + faee9d5 commit c45551a
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 78 deletions.
34 changes: 18 additions & 16 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ It accepts 3 parameters:
* `options {Object}` supported options are:
* `includeSyntaxTree {Boolean}` if true, the result object will contain the syntax tree generated by the compiler.
* `bypassJSvalidation {Boolean}` if true, the validation of the generated JS file (including non-template code) is bypassed - default:false.
* `mode {String}` the type of module system the code shold comply with: either "commonJS" or "global"
* `mode {String}` the type of module system the code shold comply with: either "commonJS" or "global"
* `globalRef {String}` the name of the runtime global reference when the "global" mode is used (default: "hsp")


The returned object contains:
* `errors {Array}` the error list - each error having the following structure:
* `description {String}` a message describing the error
* `line {Number}` the error line number
* `column {Number}` the error column number
* `column {Number}` the error column number
* `code {String}` a code extract showing where the error occurs (optional)
* `code {String}` the generated JavaScript code
* `syntaxTree {JSON}` the syntax tree generated by the parser (optional)
Expand Down Expand Up @@ -459,6 +459,8 @@ When a component template is instantiated, a new instance of its controller is c

Then, in order to be displayed for the first time, an internal refresh occurs, followed by the execution of `$refresh()` if defined.

When the component markup has been appended to the real DOM, method `$onDOMIInsert` is called.

A the end of the life cycle, when the component is not needed anymore, the `$dipose()` method, if defined, is executed.

---
Expand Down Expand Up @@ -591,7 +593,7 @@ Hashspace natively supports different types of attributes:

In order to use a `template` attribute, the template controller has to declare an attribute of such a type.

When the component content is defined, it is automatically bound to this attribute (if only a `template` attribute is defined), or to the only attribute having the defaultContent flag set to true.
When the component content is defined, it is automatically bound to this attribute (if only a `template` attribute is defined), or to the only attribute having the defaultContent flag set to true.

---

Expand Down Expand Up @@ -824,15 +826,15 @@ var ClassC = klass({
$constructor : function (incr) {
ClassB.$constructor.call(this);
this.idx += incr;
}
});
}
});
```

#### Model updates

##### Object update

To implement data-binding, Hashspace reprocesses JavaScript to introduce a partial polyfill to Object.observe and detect changes that occur to JavaScript objects. Hashspace actually uses a transpiler to encapsulate assignments with an internal `$set()` method that performs the assignment and notifies the potential observers.
To implement data-binding, Hashspace reprocesses JavaScript to introduce a partial polyfill to Object.observe and detect changes that occur to JavaScript objects. Hashspace actually uses a transpiler to encapsulate assignments with an internal `$set()` method that performs the assignment and notifies the potential observers.

In the mid-term the $set() utility will become obsolete, once the Object.observe feature is implemented by all web-browsers, and Hashspace will rely on the browser's Object.observe implementation.

Expand Down Expand Up @@ -1018,7 +1020,7 @@ A test context is a function object that exposes the following properties and me

It performs the assignment, notifies the potential observers and forces an hashspace refresh.

Parameters:
Parameters:
* {Object} `container` the object that contains a property to be set
* {String} `property` the property to be set
* {Object} `value` the value to be assigned to the given property
Expand All @@ -1033,7 +1035,7 @@ A test context is a function object that exposes the following properties and me

This method returns an array (if the parameter is not specified), otherwise it returns the corresponding log message.

Parameters:
Parameters:
* {integer} `idx` the position of the log message (first index = 0)

Furthermore, the logs object exposes the following method:
Expand All @@ -1043,11 +1045,11 @@ A test context is a function object that exposes the following properties and me

#### Selector accessor `.(selector)`

Using the `TestContext` function it is possible to retrive an array of DOM elements, filtered according to the provided selector (as it is done in jQuery by means of the `$` object); it returns a `SelectionWrapper` object.
Using the `TestContext` function it is possible to retrive an array of DOM elements, filtered according to the provided selector (as it is done in jQuery by means of the `$` object); it returns a `SelectionWrapper` object.

i.e:
```javascript
var HEAD = testCtxt(".panel .head");
var HEAD = testCtxt(".panel .head");
```

---
Expand All @@ -1060,15 +1062,15 @@ An instance of `SelectionWrapper` provides the following methods:

It permits to further refine the selection by applying a new selector.

Parameters:
Parameters:
* {String} `selector`: the selector expression (jquery selector syntax)


* ###### `text(trim)`

It returns the textual content of the selection (by recursively going through all DOM sub-nodes) and concatenates the different text node content.

Parameters:
Parameters:
* {Boolean} `trim`: whether the returned text has to be trimmed - true by default


Expand All @@ -1081,23 +1083,23 @@ An instance of `SelectionWrapper` provides the following methods:

It returns the value of an attribute of the selected node (it only works on single-element selections).

Parameters:
Parameters:
* {String} `attName` the name of the attribute - e.g. "title"


* ###### `hasClass(cssClassName)`

This method tells if the first element in the selection is assigned a specified CSS class.

Parameters:
Parameters:
* {String} `cssClassName` the class name to check


* ###### `item(idx)`

It returns the selection corresponding to the nth element in the selection.

Parameters:
Parameters:
* {integer} `idx` the position of the element (first index = 0)


Expand All @@ -1115,7 +1117,7 @@ An instance of `SelectionWrapper` provides the following methods:

It simulates a type event and triggers an hashspace refresh

Parameters:
Parameters:
* {String} `text` the text to be typed


Expand Down
3 changes: 2 additions & 1 deletion docs/samples/thirdpartycpts/description.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ Wrapping a 3rd party widget into a component involves at least 2 methods:
- **$refresh()** which is an optional method that the component controller may implement. This method is automatically called when one of the component attribute changes - right after the component's template has been refreshed. As a consequence it is the right place to tell the 3rd party library used by the component to update its DOM.
- **$getElement(index)** that is automatically added to component controllers that implement *$refresh()*and that allows to retrieve any root ELEMENT_NODEs generated by the component's template. In other words, this method allows to directly access the DOM generated by the component (as you can guess the index argument refers to the element's index - but note that non-element nodes are ignored and cannot be retrieved). As Hashspace may manipulate the DOM, this method should be used with care, preferably on Element nodes that have few interactions with Hashspace (such as the *canvas* element of this example)

As a reminder there are 2 other methods that are likely to be used on component's controllers when wrapping 3rd party libraries:
As a reminder there are 3 other methods that are likely to be used on component's controllers when wrapping 3rd party libraries:

- **$init(parent)** which is an optional initialization method that is called when the component's attributes have been initialized with the values assigned in the component's instance (in this example, the *width* attribute value would be 380 in $init() and not 100 which is the default value)
- **$onDOMInsert()** which is an optional method that is called when the component's markup is appended to the actual DOM
- **$dispose()** which is an optional method called just before the component is destroyed. This method allows object references that could cause memory leaks to be cleaned (e.g. DOM reference kept in the component's controller).

[Chart.js]: http://chartjs.org
3 changes: 3 additions & 0 deletions hsp/rt/$foreach.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ var $ForEachNode = klass({
for (var i = 0, sz = this.childNodes.length; sz > i; i++) {
this.childNodes[i].replaceNodeBy(df, this.node);
}
this.afterDOMInsert();

// TODO delete and recreate foreach items on a doc fragment
// Note: updateCollection could be used as well in this case - but when the whole collection
Expand Down Expand Up @@ -240,6 +241,7 @@ var $ForEachNode = klass({
}
this.node.insertBefore(ni.node, refNode);
ni.replaceNodeBy(ni.node, this.node);
ni.afterDOMInsert();
// update current array
current.splice(i, 0, titm);
sz += 1;
Expand Down Expand Up @@ -271,6 +273,7 @@ var $ForEachNode = klass({
// create new item
var ni = this.createItem(titm, i, i === 0, i === maxsz - 1, doc.createDocumentFragment());
this.node.insertBefore(ni.node, this.node2);
ni.afterDOMInsert();
ni.replaceNodeBy(ni.node, this.node);
}
}
Expand Down
3 changes: 3 additions & 0 deletions hsp/rt/$if.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ var $IfNode = klass({
}
this.replaceNodeBy(this.node, this.parent.node); // recursively remove doc fragment reference
this.node.insertBefore(df, this.node2);
if (this.rendered) {
this.afterDOMInsert();
}
this.isDOMempty = false;
}
}
Expand Down
46 changes: 22 additions & 24 deletions hsp/rt/$root.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ var CPT_TYPES={
var DOCUMENT_FRAGMENT_NODE = 11;

/**
* Root node - created at the root of each template
* Contains the listeners requested by the child nodes
* Root node - created at the root of each template
* Contains the listeners requested by the child nodes
* Is replaced by the $CptNode (child class) when the template is inserted in another template
*/
var $RootNode = klass({
Expand Down Expand Up @@ -265,25 +265,23 @@ var $RootNode = klass({
// recursively updates all reference to the previous doc fragment node
this.replaceNodeBy(df, c);
}
this._triggersAfterRender(this);
this.afterDOMInsert();
return this;
},

/**
* Recursively triggers the $afterRender method in all controllers of the TNode root and its children.
* @param {TNode} the root
* Recursively call the afterDOMInsert method in child nodes and the $onDOMInsert method in the controller, if any.
*/
_triggersAfterRender:function (tnode) {
if (tnode.childNodes && tnode.childNodes.length > 0) {
for (var i = 0; i < tnode.childNodes.length; i++) {
this._triggersAfterRender(tnode.childNodes[i]);
}
}
if (tnode.controller && tnode.controller.$afterRender) {
tnode.controller.$afterRender();
afterDOMInsert:function () {
TNode.afterDOMInsert.call(this);
if (this.controller && this.controller.$onDOMInsert) {
this.controller.$onDOMInsert();
}
}
});



});

/**
* Return the object referenced by the path given as argument
Expand Down Expand Up @@ -411,7 +409,7 @@ var $CptNode = klass({
ni.node2=node2;

if (p.cptType==="$CptAttInsert") {
// this cpt is used to an insert another component passed as attribute
// this cpt is used to an insert another component passed as attribute
ni.initCpt(po);
} else {
// we are in a template or component cpt
Expand All @@ -425,20 +423,20 @@ var $CptNode = klass({
// create an element to avoid generating other errors
ni=this.createCptInstance("$CptAttInsert",parent);
}

return ni;
},

/**
* Calculates the object referenced by the path and the component type
* @return {Object} object with the following properties:
* pathObject: {Object} the object referenced by the path
* cptType: {String} one of the following option: "$CptComponent",
* cptType: {String} one of the following option: "$CptComponent",
* "$CptTemplate", "$CptAttInsert" or "InvalidComponent"
*/
getPathData:function(path, vscope) {
// determine the type of this component:
// - either a template - e.g. <#mytemplate foo="bar"/>
// determine the type of this component:
// - either a template - e.g. <#mytemplate foo="bar"/>
// -> instance will extend $CptTemplate
// - a component with controller - e.g. <#mycpt foo="bar"/>
// -> instance will extend $CptComponent
Expand Down Expand Up @@ -513,7 +511,7 @@ var $CptNode = klass({
nd.appendChild(this.node2);
}
},

/**
* Callback called when a controller attribute or a template attribute has changed
*/
Expand Down Expand Up @@ -604,7 +602,7 @@ var $CptNode = klass({
} else {
if (this.refreshAttributes) {
this.refreshAttributes();
// for component and sub-templates the original vscope is substituted
// for component and sub-templates the original vscope is substituted
// to the one of the component- or sub-template
// so we need to revert to the parent scope to observe the correct objects
var vs=this.vscope;
Expand Down Expand Up @@ -668,7 +666,7 @@ var $CptNode = klass({
var sz=pos.length;

this._pathChgeCb = this.onPathChange.bind(this);

for (var i=0;sz>i;i++) {
json.observe(pos[i], this._pathChgeCb);
}
Expand Down Expand Up @@ -747,7 +745,7 @@ var $CptAttElement = klass({
isCptAttElement : true,

/**
* $CptAttElement generator
* $CptAttElement generator
*/
$constructor : function (name, exps, attcfg, ehcfg, children) {
this.name = name;
Expand Down Expand Up @@ -789,7 +787,7 @@ var $CptAttElement = klass({
if (p.ctlAttributes) {
attDef=p.ctlAttributes[this.name];
}

if (!eltDef && !attDef) {
// invalid elt
log.error(this.info+" Element not supported by its parent component");
Expand Down
16 changes: 15 additions & 1 deletion hsp/rt/tnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var TNode = klass({
isCptContent : false, // tells if a node instance is a child of a component (used to raise edirty flags)
obsPairs : null, // Array of observed [obj, property] pairs associated to this object
needSubScope : false, // true if a dedicated sub-scope should be created for this node
rendered : false,

$constructor : function (exps,observeExpTarget) {
this.isStatic = (exps === 0);
Expand Down Expand Up @@ -358,7 +359,7 @@ var TNode = klass({
} else if (nd===n1) {
process=true;
}

}
}
return null;
Expand Down Expand Up @@ -418,7 +419,20 @@ var TNode = klass({
} else {
return "INDEFINITE";
}
},

/**
* Recursively call the afterDOMInsert method in child nodes.
*/
afterDOMInsert:function () {
this.rendered = true;
if (this.childNodes && this.childNodes.length > 0) {
for (var i = 0; i < this.childNodes.length; i++) {
this.childNodes[i].afterDOMInsert();
}
}
}

});

/**
Expand Down

0 comments on commit c45551a

Please sign in to comment.