Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
todomvc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Sven Franck
todomvc
Commits
9df98e41
Commit
9df98e41
authored
Nov 22, 2014
by
Olivier Scherrer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Olives: Update Olives and Emily to latest 1.x versions
parent
b9c3b488
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
3934 additions
and
2909 deletions
+3934
-2909
examples/olives/bower.json
examples/olives/bower.json
+2
-2
examples/olives/bower_components/emily/build/Emily.js
examples/olives/bower_components/emily/build/Emily.js
+1423
-1005
examples/olives/bower_components/olives/build/Olives.js
examples/olives/bower_components/olives/build/Olives.js
+1518
-964
examples/olives/bower_components/olives/src/Bind.plugin.js
examples/olives/bower_components/olives/src/Bind.plugin.js
+604
-573
examples/olives/bower_components/olives/src/DomUtils.js
examples/olives/bower_components/olives/src/DomUtils.js
+2
-0
examples/olives/bower_components/olives/src/Event.plugin.js
examples/olives/bower_components/olives/src/Event.plugin.js
+118
-116
examples/olives/bower_components/olives/src/LocalStore.js
examples/olives/bower_components/olives/src/LocalStore.js
+3
-1
examples/olives/bower_components/olives/src/OObject.js
examples/olives/bower_components/olives/src/OObject.js
+180
-174
examples/olives/bower_components/olives/src/Place.plugin.js
examples/olives/bower_components/olives/src/Place.plugin.js
+67
-65
examples/olives/bower_components/olives/src/Plugins.js
examples/olives/bower_components/olives/src/Plugins.js
+2
-0
examples/olives/bower_components/olives/src/SocketIOTransport.js
...s/olives/bower_components/olives/src/SocketIOTransport.js
+15
-9
No files found.
examples/olives/bower.json
View file @
9df98e41
...
@@ -2,8 +2,8 @@
...
@@ -2,8 +2,8 @@
"name"
:
"todomvc-olives"
,
"name"
:
"todomvc-olives"
,
"version"
:
"0.0.0"
,
"version"
:
"0.0.0"
,
"dependencies"
:
{
"dependencies"
:
{
"olives"
:
"~1.
4
.0"
,
"olives"
:
"~1.
6
.0"
,
"emily"
:
"~1.
3.5
"
,
"emily"
:
"~1.
8.1
"
,
"requirejs"
:
"~2.1.5"
,
"requirejs"
:
"~2.1.5"
,
"todomvc-common"
:
"~0.3.0"
"todomvc-common"
:
"~0.3.0"
}
}
...
...
examples/olives/bower_components/emily/build/Emily.js
View file @
9df98e41
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*/
*/
/**
/**
* Emily
* Emily
.js - http://flams.github.com/emily/
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* MIT Licensed
* MIT Licensed
*/
*/
...
@@ -19,303 +19,372 @@ define('Tools',[],
...
@@ -19,303 +19,372 @@ define('Tools',[],
*/
*/
function
Tools
(){
function
Tools
(){
return
{
/**
* For applications that don't run in a browser, window is not the global object.
* This function returns the global object wherever the application runs.
* @returns {Object} the global object
*/
getGlobal
:
function
getGlobal
()
{
var
func
=
function
()
{
return
this
;
};
return
func
.
call
(
null
);
},
/**
/**
* Mixes an object into another
* Get the closest number in an array
* @param {Object} source object to get values from
* @param {Number} item the base number
* @param {Object} destination object to mix values into
* @param {Array} array the array to search into
* @param {Boolean} optional, set to true to prevent overriding
* @param {Function} getDiff returns the difference between the base number and
* @returns {Object} the destination object
* and the currently read item in the array. The item which returned the smallest difference wins.
*/
* @private
mixin
:
function
mixin
(
source
,
destination
,
dontOverride
)
{
*/
this
.
loop
(
source
,
function
(
value
,
idx
)
{
function
_getClosest
(
item
,
array
,
getDiff
)
{
if
(
!
destination
[
idx
]
||
!
dontOverride
)
{
var
closest
,
destination
[
idx
]
=
source
[
idx
];
diff
;
}
});
return
destination
;
},
/**
if
(
!
array
)
{
* Count the number of properties in an object
return
;
* It doesn't look up in the prototype chain
}
* @param {Object} object the object to count
* @returns {Number}
*/
count
:
function
count
(
object
)
{
var
nbItems
=
0
;
this
.
loop
(
object
,
function
()
{
nbItems
++
;
});
return
nbItems
;
array
.
forEach
(
function
(
comparedItem
,
comparedItemIndex
)
{
},
var
thisDiff
=
getDiff
(
comparedItem
,
item
);
/**
if
(
thisDiff
>=
0
&&
(
typeof
diff
==
"
undefined
"
||
thisDiff
<
diff
))
{
* Compares the properties of two objects and returns true if they're the same
diff
=
thisDiff
;
* It's doesn't do it recursively
closest
=
comparedItemIndex
;
* @param {Object} first object
}
* @param {Object} second object
});
* @returns {Boolean} true if the two objets have the same properties
*/
compareObjects
:
function
compareObjects
(
object1
,
object2
)
{
var
getOwnProperties
=
function
(
object
)
{
return
Object
.
getOwnPropertyNames
(
object
).
sort
().
join
(
""
);
};
return
getOwnProperties
(
object1
)
==
getOwnProperties
(
object2
);
},
/**
return
closest
;
* Compares two numbers and tells if the first one is bigger (1), smaller (-1) or equal (0)
}
* @param {Number} number1 the first number
* @param {Number} number2 the second number
* @returns 1 if number1>number2, -1 if number2>number1, 0 if equal
*/
compareNumbers
:
function
compareNumbers
(
number1
,
number2
)
{
if
(
number1
>
number2
)
{
return
1
;
}
else
if
(
number1
<
number2
)
{
return
-
1
;
}
else
{
return
0
;
}
},
/**
return
{
* Transform array-like objects to array, such as nodeLists or arguments
/**
* @param {Array-like object}
* For applications that don't run in a browser, window is not the global object.
* @returns {Array}
* This function returns the global object wherever the application runs.
*/
* @returns {Object} the global object
toArray
:
function
toArray
(
array
)
{
*/
return
[].
slice
.
call
(
array
);
getGlobal
:
function
getGlobal
()
{
},
var
func
=
function
()
{
return
this
;
};
return
func
.
call
(
null
);
},
/**
/**
* Small adapter for looping over objects and arrays
* Mixes an object into another
* Warning: it's not meant to be used with nodeList
* @param {Object} source object to get values from
* To use with nodeList, convert to array first
* @param {Object} destination object to mix values into
* @param {Array/Object} iterated the array or object to loop through
* @param {Boolean} optional, set to true to prevent overriding
* @param {Function} callback the function to execute for each iteration
* @returns {Object} the destination object
* @param {Object} scope the scope in which to execute the callback
*/
* @returns {Boolean} true if executed
mixin
:
function
mixin
(
source
,
destination
,
dontOverride
)
{
*/
this
.
loop
(
source
,
function
(
value
,
idx
)
{
loop
:
function
loop
(
iterated
,
callback
,
scope
)
{
if
(
!
destination
[
idx
]
||
!
dontOverride
)
{
var
i
,
destination
[
idx
]
=
source
[
idx
];
length
;
}
});
if
(
iterated
instanceof
Object
&&
callback
instanceof
Function
)
{
return
destination
;
if
(
iterated
instanceof
Array
)
{
},
for
(
i
=
0
;
i
<
iterated
.
length
;
i
++
)
{
callback
.
call
(
scope
,
iterated
[
i
],
i
,
iterated
);
}
}
else
{
for
(
i
in
iterated
)
{
if
(
iterated
.
hasOwnProperty
(
i
))
{
callback
.
call
(
scope
,
iterated
[
i
],
i
,
iterated
);
}
}
}
return
true
;
}
else
{
return
false
;
}
},
/**
/**
* Make a diff between two objects
* Count the number of properties in an object
* @param {Array/Object} before is the object as it was before
* It doesn't look up in the prototype chain
* @param {Array/Object} after is what it is now
* @param {Object} object the object to count
* @example:
* @returns {Number}
* With objects:
*/
*
count
:
function
count
(
object
)
{
* before = {a:1, b:2, c:3, d:4, f:6}
var
nbItems
=
0
;
* after = {a:1, b:20, d: 4, e: 5}
this
.
loop
(
object
,
function
()
{
* will return :
nbItems
++
;
* {
});
* unchanged: ["a", "d"],
* updated: ["b"],
* deleted: ["f"],
* added: ["e"]
* }
*
* It also works with Arrays:
*
* before = [10, 20, 30]
* after = [15, 20]
* will return :
* {
* unchanged: [1],
* updated: [0],
* deleted: [2],
* added: []
* }
*
* @returns object
*/
objectsDiffs
:
function
objectsDiffs
(
before
,
after
)
{
if
(
before
instanceof
Object
&&
after
instanceof
Object
)
{
var
unchanged
=
[],
updated
=
[],
deleted
=
[],
added
=
[];
// Look through the after object
this
.
loop
(
after
,
function
(
value
,
idx
)
{
// To get the added
if
(
typeof
before
[
idx
]
==
"
undefined
"
)
{
added
.
push
(
idx
);
// The updated
}
else
if
(
value
!==
before
[
idx
])
{
updated
.
push
(
idx
);
// And the unchanged
}
else
if
(
value
===
before
[
idx
])
{
unchanged
.
push
(
idx
);
}
});
// Loop through the before object
this
.
loop
(
before
,
function
(
value
,
idx
)
{
// To get the deleted
if
(
typeof
after
[
idx
]
==
"
undefined
"
)
{
deleted
.
push
(
idx
);
}
});
return
{
updated
:
updated
,
unchanged
:
unchanged
,
added
:
added
,
deleted
:
deleted
};
}
else
{
return
nbItems
;
return
false
;
},
}
},
/**
/**
* Transforms Arrays and Objects into valid JSON
* Compares the properties of two objects and returns true if they're the same
* @param {Object/Array} object the object to JSONify
* It's doesn't do it recursively
* @returns the JSONified object or false if failed
* @param {Object} first object
*/
* @param {Object} second object
jsonify
:
function
jsonify
(
object
)
{
* @returns {Boolean} true if the two objets have the same properties
if
(
object
instanceof
Object
)
{
*/
return
JSON
.
parse
(
JSON
.
stringify
(
object
));
compareObjects
:
function
compareObjects
(
object1
,
object2
)
{
}
else
{
var
getOwnProperties
=
function
(
object
)
{
return
false
;
return
Object
.
getOwnPropertyNames
(
object
).
sort
().
join
(
""
);
}
};
},
return
getOwnProperties
(
object1
)
==
getOwnProperties
(
object2
);
},
/**
/**
* Clone an Array or an Object
* Compares two numbers and tells if the first one is bigger (1), smaller (-1) or equal (0)
* @param {Array/Object} object the object to clone
* @param {Number} number1 the first number
* @returns {Array/Object} the cloned object
* @param {Number} number2 the second number
*/
* @returns 1 if number1>number2, -1 if number2>number1, 0 if equal
clone
:
function
clone
(
object
)
{
*/
if
(
object
instanceof
Array
)
{
compareNumbers
:
function
compareNumbers
(
number1
,
number2
)
{
return
object
.
slice
(
0
);
if
(
number1
>
number2
)
{
}
else
if
(
typeof
object
==
"
object
"
&&
object
!==
null
&&
!
(
object
instanceof
RegExp
))
{
return
1
;
return
this
.
mixin
(
object
,
{});
}
else
if
(
number1
<
number2
)
{
}
else
{
return
-
1
;
return
false
;
}
else
{
}
return
0
;
},
}
},
/**
* Transform array-like objects to array, such as nodeLists or arguments
* @param {Array-like object}
* @returns {Array}
*/
toArray
:
function
toArray
(
array
)
{
return
[].
slice
.
call
(
array
);
},
/**
/**
*
* Small adapter for looping over objects and arrays
*
* Warning: it's not meant to be used with nodeList
*
* To use with nodeList, convert to array first
*
* @param {Array/Object} iterated the array or object to loop through
* Refactoring needed for the following
* @param {Function} callback the function to execute for each iteration
*
* @param {Object} scope the scope in which to execute the callback
*
* @returns {Boolean} true if executed
*
*/
*
loop
:
function
loop
(
iterated
,
callback
,
scope
)
{
*
var
i
,
*/
length
;
if
(
iterated
instanceof
Object
&&
callback
instanceof
Function
)
{
if
(
iterated
instanceof
Array
)
{
for
(
i
=
0
;
i
<
iterated
.
length
;
i
++
)
{
callback
.
call
(
scope
,
iterated
[
i
],
i
,
iterated
);
}
}
else
{
for
(
i
in
iterated
)
{
if
(
iterated
.
hasOwnProperty
(
i
))
{
callback
.
call
(
scope
,
iterated
[
i
],
i
,
iterated
);
}
}
}
return
true
;
}
else
{
return
false
;
}
},
/**
/**
* Get the property of an object nested in one or more objects
* Make a diff between two objects
* given an object such as a.b.c.d = 5, getNestedProperty(a, "b.c.d") will return 5.
* @param {Array/Object} before is the object as it was before
* @param {Object} object the object to get the property from
* @param {Array/Object} after is what it is now
* @param {String} property the path to the property as a string
* @example:
* @returns the object or the the property value if found
* With objects:
*/
*
getNestedProperty
:
function
getNestedProperty
(
object
,
property
)
{
* before = {a:1, b:2, c:3, d:4, f:6}
if
(
object
&&
object
instanceof
Object
)
{
* after = {a:1, b:20, d: 4, e: 5}
if
(
typeof
property
==
"
string
"
&&
property
!=
""
)
{
* will return :
var
split
=
property
.
split
(
"
.
"
);
* {
return
split
.
reduce
(
function
(
obj
,
prop
)
{
* unchanged: ["a", "d"],
return
obj
&&
obj
[
prop
];
* updated: ["b"],
},
object
);
* deleted: ["f"],
}
else
if
(
typeof
property
==
"
number
"
)
{
* added: ["e"]
return
object
[
property
];
* }
}
else
{
*
return
object
;
* It also works with Arrays:
}
*
}
else
{
* before = [10, 20, 30]
return
object
;
* after = [15, 20]
}
* will return :
},
* {
* unchanged: [1],
* updated: [0],
* deleted: [2],
* added: []
* }
*
* @returns object
*/
objectsDiffs
:
function
objectsDiffs
(
before
,
after
)
{
if
(
before
instanceof
Object
&&
after
instanceof
Object
)
{
var
unchanged
=
[],
updated
=
[],
deleted
=
[],
added
=
[];
// Look through the after object
this
.
loop
(
after
,
function
(
value
,
idx
)
{
// To get the added
if
(
typeof
before
[
idx
]
==
"
undefined
"
)
{
added
.
push
(
idx
);
// The updated
}
else
if
(
value
!==
before
[
idx
])
{
updated
.
push
(
idx
);
// And the unchanged
}
else
if
(
value
===
before
[
idx
])
{
unchanged
.
push
(
idx
);
}
});
// Loop through the before object
this
.
loop
(
before
,
function
(
value
,
idx
)
{
// To get the deleted
if
(
typeof
after
[
idx
]
==
"
undefined
"
)
{
deleted
.
push
(
idx
);
}
});
return
{
updated
:
updated
,
unchanged
:
unchanged
,
added
:
added
,
deleted
:
deleted
};
}
else
{
return
false
;
}
},
/**
/**
* Set the property of an object nested in one or more objects
* Transforms Arrays and Objects into valid JSON
* If the property doesn't exist, it gets created.
* @param {Object/Array} object the object to JSONify
* @param {Object} object
* @returns the JSONified object or false if failed
* @param {String} property
*/
* @param value the value to set
jsonify
:
function
jsonify
(
object
)
{
* @returns object if no assignment was made or the value if the assignment was made
if
(
object
instanceof
Object
)
{
*/
return
JSON
.
parse
(
JSON
.
stringify
(
object
));
setNestedProperty
:
function
setNestedProperty
(
object
,
property
,
value
)
{
}
else
{
if
(
object
&&
object
instanceof
Object
)
{
return
false
;
if
(
typeof
property
==
"
string
"
&&
property
!=
""
)
{
}
var
split
=
property
.
split
(
"
.
"
);
},
return
split
.
reduce
(
function
(
obj
,
prop
,
idx
)
{
obj
[
prop
]
=
obj
[
prop
]
||
{};
if
(
split
.
length
==
(
idx
+
1
))
{
obj
[
prop
]
=
value
;
}
return
obj
[
prop
];
},
object
);
}
else
if
(
typeof
property
==
"
number
"
)
{
object
[
property
]
=
value
;
return
object
[
property
];
}
else
{
return
object
;
}
}
else
{
return
object
;
}
}
/**
* Clone an Array or an Object
* @param {Array/Object} object the object to clone
* @returns {Array/Object} the cloned object
*/
clone
:
function
clone
(
object
)
{
if
(
object
instanceof
Array
)
{
return
object
.
slice
(
0
);
}
else
if
(
typeof
object
==
"
object
"
&&
object
!==
null
&&
!
(
object
instanceof
RegExp
))
{
return
this
.
mixin
(
object
,
{});
}
else
{
return
false
;
}
},
};
/**
*
*
*
*
* Refactoring needed for the following
*
*
*
*
*
*/
/**
* Get the property of an object nested in one or more objects
* given an object such as a.b.c.d = 5, getNestedProperty(a, "b.c.d") will return 5.
* @param {Object} object the object to get the property from
* @param {String} property the path to the property as a string
* @returns the object or the the property value if found
*/
getNestedProperty
:
function
getNestedProperty
(
object
,
property
)
{
if
(
object
&&
object
instanceof
Object
)
{
if
(
typeof
property
==
"
string
"
&&
property
!==
""
)
{
var
split
=
property
.
split
(
"
.
"
);
return
split
.
reduce
(
function
(
obj
,
prop
)
{
return
obj
&&
obj
[
prop
];
},
object
);
}
else
if
(
typeof
property
==
"
number
"
)
{
return
object
[
property
];
}
else
{
return
object
;
}
}
else
{
return
object
;
}
},
/**
* Set the property of an object nested in one or more objects
* If the property doesn't exist, it gets created.
* @param {Object} object
* @param {String} property
* @param value the value to set
* @returns object if no assignment was made or the value if the assignment was made
*/
setNestedProperty
:
function
setNestedProperty
(
object
,
property
,
value
)
{
if
(
object
&&
object
instanceof
Object
)
{
if
(
typeof
property
==
"
string
"
&&
property
!==
""
)
{
var
split
=
property
.
split
(
"
.
"
);
return
split
.
reduce
(
function
(
obj
,
prop
,
idx
)
{
obj
[
prop
]
=
obj
[
prop
]
||
{};
if
(
split
.
length
==
(
idx
+
1
))
{
obj
[
prop
]
=
value
;
}
return
obj
[
prop
];
},
object
);
}
else
if
(
typeof
property
==
"
number
"
)
{
object
[
property
]
=
value
;
return
object
[
property
];
}
else
{
return
object
;
}
}
else
{
return
object
;
}
},
/**
* Get the closest number in an array given a base number
* Example: closest(30, [20, 0, 50, 29]) will return 3 as 29 is the closest item
* @param {Number} item the base number
* @param {Array} array the array of numbers to search into
* @returns {Number} the index of the closest item in the array
*/
closest
:
function
closest
(
item
,
array
)
{
return
_getClosest
(
item
,
array
,
function
(
comparedItem
,
item
)
{
return
Math
.
abs
(
comparedItem
-
item
);
});
},
/**
* Get the closest greater number in an array given a base number
* Example: closest(30, [20, 0, 50, 29]) will return 2 as 50 is the closest greater item
* @param {Number} item the base number
* @param {Array} array the array of numbers to search into
* @returns {Number} the index of the closest item in the array
*/
closestGreater
:
function
closestGreater
(
item
,
array
)
{
return
_getClosest
(
item
,
array
,
function
(
comparedItem
,
item
)
{
return
comparedItem
-
item
;
});
},
/**
* Get the closest lower number in an array given a base number
* Example: closest(30, [20, 0, 50, 29]) will return 0 as 20 is the closest lower item
* @param {Number} item the base number
* @param {Array} array the array of numbers to search into
* @returns {Number} the index of the closest item in the array
*/
closestLower
:
function
closestLower
(
item
,
array
)
{
return
_getClosest
(
item
,
array
,
function
(
comparedItem
,
item
)
{
return
item
-
comparedItem
;
});
}
};
});
});
/**
/**
* Emily
* Emily
.js - http://flams.github.com/emily/
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* MIT Licensed
* MIT Licensed
*/
*/
...
@@ -330,6 +399,8 @@ define('Observable',["Tools"],
...
@@ -330,6 +399,8 @@ define('Observable',["Tools"],
*/
*/
function
Observable
(
Tools
)
{
function
Observable
(
Tools
)
{
/**
/**
* Defines the Observable
* Defines the Observable
* @private
* @private
...
@@ -363,6 +434,21 @@ function Observable(Tools) {
...
@@ -363,6 +434,21 @@ function Observable(Tools) {
}
}
};
};
/**
* Listen to an event just once before removing the handler
* @param {String} topic the topic to observe
* @param {Function} callback the callback to execute
* @param {Object} scope the scope in which to execute the callback
* @returns handle
*/
this
.
once
=
function
once
(
topic
,
callback
,
scope
)
{
var
handle
=
this
.
watch
(
topic
,
function
()
{
callback
.
apply
(
scope
,
arguments
);
this
.
unwatch
(
handle
);
},
this
);
return
handle
;
};
/**
/**
* Remove an observer
* Remove an observer
* @param {Handle} handle returned by the watch method
* @param {Handle} handle returned by the watch method
...
@@ -398,14 +484,16 @@ function Observable(Tools) {
...
@@ -398,14 +484,16 @@ function Observable(Tools) {
if
(
observers
)
{
if
(
observers
)
{
Tools
.
loop
(
observers
,
function
(
value
)
{
Tools
.
loop
(
observers
,
function
(
value
)
{
try
{
try
{
value
&&
value
[
0
].
apply
(
value
[
1
]
||
null
,
args
);
if
(
value
)
{
value
[
0
].
apply
(
value
[
1
]
||
null
,
args
);
}
}
catch
(
err
)
{
}
}
catch
(
err
)
{
}
});
});
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
}
,
}
;
/**
/**
* Check if topic has the described observer
* Check if topic has the described observer
...
@@ -444,7 +532,7 @@ function Observable(Tools) {
...
@@ -444,7 +532,7 @@ function Observable(Tools) {
});
});
/**
/**
* Emily
* Emily
.js - http://flams.github.com/emily/
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* MIT Licensed
* MIT Licensed
*/
*/
...
@@ -456,7 +544,9 @@ define('StateMachine',["Tools"],
...
@@ -456,7 +544,9 @@ define('StateMachine',["Tools"],
*/
*/
function
StateMachine
(
Tools
)
{
function
StateMachine
(
Tools
)
{
/**
/**
* @param initState {String} the initial state
* @param initState {String} the initial state
* @param diagram {Object} the diagram that describes the state machine
* @param diagram {Object} the diagram that describes the state machine
* @example
* @example
...
@@ -475,228 +565,229 @@ function StateMachine(Tools) {
...
@@ -475,228 +565,229 @@ function StateMachine(Tools) {
*
*
* @return the stateMachine object
* @return the stateMachine object
*/
*/
function
StateMachineConstructor
(
$initState
,
$diagram
)
{
function
StateMachineConstructor
(
$initState
,
$diagram
)
{
/**
* The list of states
* @private
*/
var
_states
=
{},
/**
/**
* The current state
* The list of states
* @private
* @private
*/
*/
_currentState
=
""
;
var
_states
=
{},
/**
/**
* Set the initialization state
* The current state
* @param {String} name the name of the init state
* @private
* @returns {Boolean}
*/
*/
_currentState
=
""
;
this
.
init
=
function
init
(
name
)
{
if
(
_states
[
name
])
{
_currentState
=
name
;
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Add a new
state
* Set the initialization
state
* @priv
ate
* @param {String} name the name of the init st
ate
* @param {String} name the name of the state
* @returns {Boolean}
* @returns {State} a new state
*/
*/
this
.
init
=
function
init
(
name
)
{
this
.
add
=
function
add
(
name
)
{
if
(
_states
[
name
]
)
{
if
(
!
_states
[
name
])
{
_currentState
=
name
;
return
_states
[
name
]
=
new
Transition
()
;
return
true
;
}
else
{
}
else
{
return
_states
[
name
]
;
return
false
;
}
}
};
};
/**
/**
* Get an existing state
* Add a new state
* @private
* @private
* @param {String} name the name of the state
* @param {String} name the name of the state
* @returns {State} the state
* @returns {State} a new state
*/
*/
this
.
get
=
function
get
(
name
)
{
this
.
add
=
function
add
(
name
)
{
return
_states
[
name
];
if
(
!
_states
[
name
])
{
};
var
transition
=
_states
[
name
]
=
new
Transition
();
return
transition
;
}
else
{
return
_states
[
name
];
}
};
/**
/**
* Get the current state
* Get an existing state
* @returns {String}
* @private
*/
* @param {String} name the name of the state
this
.
getCurrent
=
function
getCurrent
()
{
* @returns {State} the state
return
_currentState
;
*/
};
this
.
get
=
function
get
(
name
)
{
return
_states
[
name
];
};
/**
/**
* Tell if the state machine has the given state
* Get the current state
* @param {String} state the name of the state
* @returns {String}
* @returns {Boolean} true if it has the given state
*/
*/
this
.
getCurrent
=
function
getCurrent
()
{
this
.
has
=
function
has
(
state
)
{
return
_currentState
;
return
_states
.
hasOwnProperty
(
state
);
};
};
/**
/**
* Advances the state machine to a given state
* Tell if the state machine has the given state
* @param {String} state the name of the state to advance the state machine to
* @param {String} state the name of the state
* @returns {Boolean} true if it has the given state
* @returns {Boolean} true if it has the given state
*/
*/
this
.
advance
=
function
advance
(
state
)
{
this
.
has
=
function
has
(
state
)
{
if
(
this
.
has
(
state
))
{
return
_states
.
hasOwnProperty
(
state
);
_currentState
=
state
;
};
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Pass an event to the state machine
* Advances the state machine to a given state
* @param {String} name the name of the event
* @param {String} state the name of the state to advance the state machine to
* @returns {Boolean} true if the event exists in the current state
* @returns {Boolean} true if it has the given state
*/
*/
this
.
event
=
function
event
(
name
)
{
this
.
advance
=
function
advance
(
state
)
{
var
nextState
;
if
(
this
.
has
(
state
))
{
_currentState
=
state
;
return
true
;
}
else
{
return
false
;
}
};
nextState
=
_states
[
_currentState
].
event
.
apply
(
_states
[
_currentState
].
event
,
Tools
.
toArray
(
arguments
));
/**
// False means that there's no such event
* Pass an event to the state machine
// But undefined means that the state doesn't change
* @param {String} name the name of the event
if
(
nextState
===
false
)
{
* @returns {Boolean} true if the event exists in the current state
return
false
;
*/
}
else
{
this
.
event
=
function
event
(
name
)
{
// There could be no next state, so the current one remains
var
nextState
;
if
(
nextState
)
{
// Call the exit action if any
nextState
=
_states
[
_currentState
].
event
.
apply
(
_states
[
_currentState
].
event
,
Tools
.
toArray
(
arguments
));
_states
[
_currentState
].
event
(
"
exit
"
);
// False means that there's no such event
_currentState
=
nextState
;
// But undefined means that the state doesn't change
// Call the new state's entry action if any
if
(
nextState
===
false
)
{
_states
[
_currentState
].
event
(
"
entry
"
);
return
false
;
}
}
else
{
return
true
;
// There could be no next state, so the current one remains
}
if
(
nextState
)
{
};
// Call the exit action if any
_states
[
_currentState
].
event
(
"
exit
"
);
_currentState
=
nextState
;
// Call the new state's entry action if any
_states
[
_currentState
].
event
(
"
entry
"
);
}
return
true
;
}
};
/**
/**
* Initializes the StateMachine with the given diagram
* Initializes the StateMachine with the given diagram
*/
*/
Tools
.
loop
(
$diagram
,
function
(
transition
,
state
)
{
Tools
.
loop
(
$diagram
,
function
(
transition
,
state
)
{
var
myState
=
this
.
add
(
state
);
var
myState
=
this
.
add
(
state
);
transition
.
forEach
(
function
(
params
){
transition
.
forEach
(
function
(
params
){
myState
.
add
.
apply
(
null
,
params
);
myState
.
add
.
apply
(
null
,
params
);
});
});
},
this
);
},
this
);
/**
/**
* Sets its initial state
* Sets its initial state
*/
*/
this
.
init
(
$initState
);
this
.
init
(
$initState
);
}
}
/**
/**
* Each state has associated transitions
* Each state has associated transitions
* @constructor
* @constructor
*/
*/
function
Transition
()
{
function
Transition
()
{
/**
/**
* The list of transitions associated to a state
* The list of transitions associated to a state
* @private
* @private
*/
*/
var
_transitions
=
{};
var
_transitions
=
{};
/**
/**
* Add a new transition
* Add a new transition
* @private
* @private
* @param {String} event the event that will trigger the transition
* @param {String} event the event that will trigger the transition
* @param {Function} action the function that is executed
* @param {Function} action the function that is executed
* @param {Object} scope [optional] the scope in which to execute the action
* @param {Object} scope [optional] the scope in which to execute the action
* @param {String} next [optional] the name of the state to transit to.
* @param {String} next [optional] the name of the state to transit to.
* @returns {Boolean} true if success, false if the transition already exists
* @returns {Boolean} true if success, false if the transition already exists
*/
*/
this
.
add
=
function
add
(
event
,
action
,
scope
,
next
)
{
this
.
add
=
function
add
(
event
,
action
,
scope
,
next
)
{
var
arr
=
[];
var
arr
=
[];
if
(
_transitions
[
event
])
{
if
(
_transitions
[
event
])
{
return
false
;
return
false
;
}
}
if
(
typeof
event
==
"
string
"
if
(
typeof
event
==
"
string
"
&&
&&
typeof
action
==
"
function
"
)
{
typeof
action
==
"
function
"
)
{
arr
[
0
]
=
action
;
arr
[
0
]
=
action
;
if
(
typeof
scope
==
"
object
"
)
{
if
(
typeof
scope
==
"
object
"
)
{
arr
[
1
]
=
scope
;
arr
[
1
]
=
scope
;
}
}
if
(
typeof
scope
==
"
string
"
)
{
if
(
typeof
scope
==
"
string
"
)
{
arr
[
2
]
=
scope
;
arr
[
2
]
=
scope
;
}
}
if
(
typeof
next
==
"
string
"
)
{
if
(
typeof
next
==
"
string
"
)
{
arr
[
2
]
=
next
;
arr
[
2
]
=
next
;
}
}
_transitions
[
event
]
=
arr
;
_transitions
[
event
]
=
arr
;
return
true
;
return
true
;
}
}
return
false
;
return
false
;
};
};
/**
/**
* Check if a transition can be triggered with given event
* Check if a transition can be triggered with given event
* @private
* @private
* @param {String} event the name of the event
* @param {String} event the name of the event
* @returns {Boolean} true if exists
* @returns {Boolean} true if exists
*/
*/
this
.
has
=
function
has
(
event
)
{
this
.
has
=
function
has
(
event
)
{
return
!!
_transitions
[
event
];
return
!!
_transitions
[
event
];
};
};
/**
/**
* Get a transition from it's event
* Get a transition from it's event
* @private
* @private
* @param {String} event the name of the event
* @param {String} event the name of the event
* @return the transition
* @return the transition
*/
*/
this
.
get
=
function
get
(
event
)
{
this
.
get
=
function
get
(
event
)
{
return
_transitions
[
event
]
||
false
;
return
_transitions
[
event
]
||
false
;
};
};
/**
/**
* Execute the action associated to the given event
* Execute the action associated to the given event
* @param {String} event the name of the event
* @param {String} event the name of the event
* @param {params} params to pass to the action
* @param {params} params to pass to the action
* @private
* @private
* @returns false if error, the next state or undefined if success (that sounds weird)
* @returns false if error, the next state or undefined if success (that sounds weird)
*/
*/
this
.
event
=
function
event
(
e
vent
)
{
this
.
event
=
function
event
(
newE
vent
)
{
var
_transition
=
_transitions
[
e
vent
];
var
_transition
=
_transitions
[
newE
vent
];
if
(
_transition
)
{
if
(
_transition
)
{
_transition
[
0
].
apply
(
_transition
[
1
],
Tools
.
toArray
(
arguments
).
slice
(
1
));
_transition
[
0
].
apply
(
_transition
[
1
],
Tools
.
toArray
(
arguments
).
slice
(
1
));
return
_transition
[
2
];
return
_transition
[
2
];
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
};
}
return
StateMachineConstructor
;
return
StateMachineConstructor
;
});
});
/**
/**
* Emily
* Emily
.js - http://flams.github.com/emily/
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* MIT Licensed
* MIT Licensed
*/
*/
...
@@ -708,107 +799,109 @@ define('Promise',["Observable", "StateMachine"],
...
@@ -708,107 +799,109 @@ define('Promise',["Observable", "StateMachine"],
*/
*/
function
Promise
(
Observable
,
StateMachine
)
{
function
Promise
(
Observable
,
StateMachine
)
{
return
function
PromiseConstructor
()
{
/**
* The fulfilled value
* @private
*/
var
_value
=
null
,
/**
return
function
PromiseConstructor
()
{
* The rejection reason
* @private
*/
_reason
=
null
,
/**
/**
* The funky observabl
e
* The fulfilled valu
e
* @private
* @private
*/
*/
_observable
=
new
Observable
,
var
_value
=
null
,
/**
/**
* The state machine States & transitions
* The rejection reason
* @private
* @private
*/
*/
_states
=
{
_reason
=
null
,
// The promise is pending
"
Pending
"
:
[
// It can only be fulfilled when pending
[
"
fulfill
"
,
function
onFulfill
(
value
)
{
_value
=
value
;
_observable
.
notify
(
"
fulfill
"
,
value
);
// Then it transits to the fulfilled state
},
"
Fulfilled
"
],
// it can only be rejected when pending
[
"
reject
"
,
function
onReject
(
reason
)
{
_reason
=
reason
;
_observable
.
notify
(
"
reject
"
,
reason
);
// Then it transits to the rejected state
},
"
Rejected
"
],
// When pending, add the resolver to an observable
[
"
toFulfill
"
,
function
toFulfill
(
resolver
)
{
_observable
.
watch
(
"
fulfill
"
,
resolver
);
}],
// When pending, add the resolver to an observable
[
"
toReject
"
,
function
toReject
(
resolver
)
{
_observable
.
watch
(
"
reject
"
,
resolver
);
}]],
// When fulfilled,
"
Fulfilled
"
:
[
// We directly call the resolver with the value
[
"
toFulfill
"
,
function
toFulfill
(
resolver
)
{
setTimeout
(
function
()
{
resolver
(
_value
);
},
0
);
}]],
// When rejected
"
Rejected
"
:
[
// We directly call the resolver with the reason
[
"
toReject
"
,
function
toReject
(
resolver
)
{
setTimeout
(
function
()
{
resolver
(
_reason
);
},
0
);
}]]
},
/**
/**
* The stateMachin
e
* The funky observabl
e
* @private
* @private
*/
*/
_stateMachine
=
new
StateMachine
(
"
Pending
"
,
_states
);
_observable
=
new
Observable
(),
/**
/**
* Fulfilled the promise.
* The state machine States & transitions
* A promise can be fulfilld only once.
* @private
* @param the fulfillment value
*/
* @returns the promise
_states
=
{
*/
this
.
fulfill
=
function
fulfill
(
value
)
{
// The promise is pending
_stateMachine
.
event
(
"
fulfill
"
,
value
);
"
Pending
"
:
[
return
this
;
};
// It can only be fulfilled when pending
[
"
fulfill
"
,
function
onFulfill
(
value
)
{
_value
=
value
;
_observable
.
notify
(
"
fulfill
"
,
value
);
// Then it transits to the fulfilled state
},
"
Fulfilled
"
],
// it can only be rejected when pending
[
"
reject
"
,
function
onReject
(
reason
)
{
_reason
=
reason
;
_observable
.
notify
(
"
reject
"
,
reason
);
// Then it transits to the rejected state
},
"
Rejected
"
],
// When pending, add the resolver to an observable
[
"
toFulfill
"
,
function
toFulfill
(
resolver
)
{
_observable
.
watch
(
"
fulfill
"
,
resolver
);
}],
// When pending, add the resolver to an observable
[
"
toReject
"
,
function
toReject
(
resolver
)
{
_observable
.
watch
(
"
reject
"
,
resolver
);
}]],
// When fulfilled,
"
Fulfilled
"
:
[
// We directly call the resolver with the value
[
"
toFulfill
"
,
function
toFulfill
(
resolver
)
{
setTimeout
(
function
()
{
resolver
(
_value
);
},
0
);
}]],
// When rejected
"
Rejected
"
:
[
// We directly call the resolver with the reason
[
"
toReject
"
,
function
toReject
(
resolver
)
{
setTimeout
(
function
()
{
resolver
(
_reason
);
},
0
);
}]]
},
/**
/**
* Reject the promise.
* The stateMachine
* A promise can be rejected only once.
* @private
* @param the rejection value
*/
* @returns true if the rejection function was called
_stateMachine
=
new
StateMachine
(
"
Pending
"
,
_states
);
*/
this
.
reject
=
function
reject
(
reason
)
{
_stateMachine
.
event
(
"
reject
"
,
reason
);
return
this
;
};
/**
/**
* Fulfilled the promise.
* A promise can be fulfilld only once.
* @param the fulfillment value
* @returns the promise
*/
this
.
fulfill
=
function
fulfill
(
value
)
{
_stateMachine
.
event
(
"
fulfill
"
,
value
);
return
this
;
};
/**
* Reject the promise.
* A promise can be rejected only once.
* @param the rejection value
* @returns true if the rejection function was called
*/
this
.
reject
=
function
reject
(
reason
)
{
_stateMachine
.
event
(
"
reject
"
,
reason
);
return
this
;
};
/**
* The callbacks to call after fulfillment or rejection
* The callbacks to call after fulfillment or rejection
* @param {Function} fulfillmentCallback the first parameter is a success function, it can be followed by a scope
* @param {Function} fulfillmentCallback the first parameter is a success function, it can be followed by a scope
* @param {Function} the second, or third parameter is the rejection callback, it can also be followed by a scope
* @param {Function} the second, or third parameter is the rejection callback, it can also be followed by a scope
...
@@ -822,88 +915,88 @@ function Promise(Observable, StateMachine) {
...
@@ -822,88 +915,88 @@ function Promise(Observable, StateMachine) {
* @returns {Promise} the new promise
* @returns {Promise} the new promise
*/
*/
this
.
then
=
function
then
()
{
this
.
then
=
function
then
()
{
var
promise
=
new
PromiseConstructor
;
var
promise
=
new
PromiseConstructor
()
;
// If a fulfillment callback is given
// If a fulfillment callback is given
if
(
arguments
[
0
]
instanceof
Function
)
{
if
(
arguments
[
0
]
instanceof
Function
)
{
// If the second argument is also a function, then no scope is given
// If the second argument is also a function, then no scope is given
if
(
arguments
[
1
]
instanceof
Function
)
{
if
(
arguments
[
1
]
instanceof
Function
)
{
_stateMachine
.
event
(
"
toFulfill
"
,
this
.
makeResolver
(
promise
,
arguments
[
0
]));
_stateMachine
.
event
(
"
toFulfill
"
,
this
.
makeResolver
(
promise
,
arguments
[
0
]));
}
else
{
}
else
{
// If the second argument is not a function, it's the scope
// If the second argument is not a function, it's the scope
_stateMachine
.
event
(
"
toFulfill
"
,
this
.
makeResolver
(
promise
,
arguments
[
0
],
arguments
[
1
]));
_stateMachine
.
event
(
"
toFulfill
"
,
this
.
makeResolver
(
promise
,
arguments
[
0
],
arguments
[
1
]));
}
}
}
else
{
}
else
{
// If no fulfillment callback given, give a default one
// If no fulfillment callback given, give a default one
_stateMachine
.
event
(
"
toFulfill
"
,
this
.
makeResolver
(
promise
,
function
()
{
_stateMachine
.
event
(
"
toFulfill
"
,
this
.
makeResolver
(
promise
,
function
()
{
promise
.
fulfill
(
_value
);
promise
.
fulfill
(
_value
);
}));
}));
}
}
// if the second arguments is a callback, it's the rejection one, and the next argument is the scope
// if the second arguments is a callback, it's the rejection one, and the next argument is the scope
if
(
arguments
[
1
]
instanceof
Function
)
{
if
(
arguments
[
1
]
instanceof
Function
)
{
_stateMachine
.
event
(
"
toReject
"
,
this
.
makeResolver
(
promise
,
arguments
[
1
],
arguments
[
2
]));
_stateMachine
.
event
(
"
toReject
"
,
this
.
makeResolver
(
promise
,
arguments
[
1
],
arguments
[
2
]));
}
}
// if the third arguments is a callback, it's the rejection one, and the next arguments is the sopce
// if the third arguments is a callback, it's the rejection one, and the next arguments is the sopce
if
(
arguments
[
2
]
instanceof
Function
)
{
if
(
arguments
[
2
]
instanceof
Function
)
{
_stateMachine
.
event
(
"
toReject
"
,
this
.
makeResolver
(
promise
,
arguments
[
2
],
arguments
[
3
]));
_stateMachine
.
event
(
"
toReject
"
,
this
.
makeResolver
(
promise
,
arguments
[
2
],
arguments
[
3
]));
}
}
// If no rejection callback is given, give a default one
// If no rejection callback is given, give a default one
if
(
!
(
arguments
[
1
]
instanceof
Function
)
&&
if
(
!
(
arguments
[
1
]
instanceof
Function
)
&&
!
(
arguments
[
2
]
instanceof
Function
))
{
!
(
arguments
[
2
]
instanceof
Function
))
{
_stateMachine
.
event
(
"
toReject
"
,
this
.
makeResolver
(
promise
,
function
()
{
_stateMachine
.
event
(
"
toReject
"
,
this
.
makeResolver
(
promise
,
function
()
{
promise
.
reject
(
_reason
);
promise
.
reject
(
_reason
);
}));
}));
}
}
return
promise
;
return
promise
;
};
};
/**
/**
* Synchronize this promise with a thenable
* Synchronize this promise with a thenable
* @returns {Boolean} false if the given sync is not a thenable
* @returns {Boolean} false if the given sync is not a thenable
*/
*/
this
.
sync
=
function
sync
(
syncWith
)
{
this
.
sync
=
function
sync
(
syncWith
)
{
if
(
syncWith
instanceof
Object
&&
syncWith
.
then
)
{
if
(
syncWith
instanceof
Object
&&
syncWith
.
then
)
{
var
onFulfilled
=
function
onFulfilled
(
value
)
{
var
onFulfilled
=
function
onFulfilled
(
value
)
{
this
.
fulfill
(
value
);
this
.
fulfill
(
value
);
},
},
onRejected
=
function
onRejected
(
reason
)
{
onRejected
=
function
onRejected
(
reason
)
{
this
.
reject
(
reason
);
this
.
reject
(
reason
);
};
};
syncWith
.
then
(
onFulfilled
.
bind
(
this
),
syncWith
.
then
(
onFulfilled
.
bind
(
this
),
onRejected
.
bind
(
this
));
onRejected
.
bind
(
this
));
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Make a resolver
* Make a resolver
* for debugging only
* for debugging only
* @private
* @private
* @returns {Function} a closure
* @returns {Function} a closure
*/
*/
this
.
makeResolver
=
function
makeResolver
(
promise
,
func
,
scope
)
{
this
.
makeResolver
=
function
makeResolver
(
promise
,
func
,
scope
)
{
return
function
resolver
(
value
)
{
return
function
resolver
(
value
)
{
var
returnedPromise
;
var
returnedPromise
;
try
{
try
{
returnedPromise
=
func
.
call
(
scope
,
value
);
returnedPromise
=
func
.
call
(
scope
,
value
);
if
(
!
promise
.
sync
(
returnedPromise
))
{
if
(
!
promise
.
sync
(
returnedPromise
))
{
promise
.
fulfill
(
returnedPromise
);
promise
.
fulfill
(
returnedPromise
);
}
}
}
catch
(
err
)
{
}
catch
(
err
)
{
promise
.
reject
(
err
);
promise
.
reject
(
err
);
}
}
}
};
};
};
/**
/**
...
@@ -912,7 +1005,7 @@ function Promise(Observable, StateMachine) {
...
@@ -912,7 +1005,7 @@ function Promise(Observable, StateMachine) {
* @private
* @private
*/
*/
this
.
getReason
=
function
getReason
()
{
this
.
getReason
=
function
getReason
()
{
return
_reason
;
return
_reason
;
};
};
/**
/**
...
@@ -921,40 +1014,40 @@ function Promise(Observable, StateMachine) {
...
@@ -921,40 +1014,40 @@ function Promise(Observable, StateMachine) {
* @private
* @private
*/
*/
this
.
getValue
=
function
getValue
()
{
this
.
getValue
=
function
getValue
()
{
return
_value
;
return
_value
;
};
};
/**
/**
* Get the promise's observable
* Get the promise's observable
* for debugging only
* for debugging only
* @private
* @private
* @returns {Observable}
* @returns {Observable}
*/
*/
this
.
getObservable
=
function
getObservable
()
{
this
.
getObservable
=
function
getObservable
()
{
return
_observable
;
return
_observable
;
};
};
/**
/**
* Get the promise's stateMachine
* Get the promise's stateMachine
* for debugging only
* for debugging only
* @private
* @private
* @returns {StateMachine}
* @returns {StateMachine}
*/
*/
this
.
getStateMachine
=
function
getStateMachine
()
{
this
.
getStateMachine
=
function
getStateMachine
()
{
return
_stateMachine
;
return
_stateMachine
;
};
};
/**
/**
* Get the statesMachine's states
* Get the statesMachine's states
* for debugging only
* for debugging only
* @private
* @private
* @returns {Object}
* @returns {Object}
*/
*/
this
.
getStates
=
function
getStates
()
{
this
.
getStates
=
function
getStates
()
{
return
_states
;
return
_states
;
};
};
}
};
...
@@ -962,7 +1055,7 @@ function Promise(Observable, StateMachine) {
...
@@ -962,7 +1055,7 @@ function Promise(Observable, StateMachine) {
});
});
/**
/**
* Emily
* Emily
.js - http://flams.github.com/emily/
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* MIT Licensed
* MIT Licensed
*/
*/
...
@@ -975,297 +1068,379 @@ define('Store',["Observable", "Tools"],
...
@@ -975,297 +1068,379 @@ define('Store',["Observable", "Tools"],
*/
*/
function
Store
(
Observable
,
Tools
)
{
function
Store
(
Observable
,
Tools
)
{
/**
* Defines the Store
* @param {Array/Object} the data to initialize the store with
* @returns
*/
return
function
StoreConstructor
(
$data
)
{
/**
/**
* Where the data is stored
* Defines the Store
* @private
* @param {Array/Object} the data to initialize the store with
*/
* @returns
var
_data
=
Tools
.
clone
(
$data
)
||
{},
*/
return
function
StoreConstructor
(
$data
)
{
/**
/**
* The observable for publishing changes on the store iself
* Where the data is stored
* @private
* @private
*/
*/
_storeObservable
=
new
Observable
()
,
var
_data
=
Tools
.
clone
(
$data
)
||
{}
,
/**
/**
* The observable for publishing changes on a value
* The observable for publishing changes on the store iself
* @private
* @private
*/
*/
_valu
eObservable
=
new
Observable
(),
_stor
eObservable
=
new
Observable
(),
/**
/**
* Gets the difference between two objects and notifies them
* The observable for publishing changes on a value
* @private
* @private
* @param {Object} previousData
*/
*/
_valueObservable
=
new
Observable
(),
_notifyDiffs
=
function
_notifyDiffs
(
previousData
)
{
var
diffs
=
Tools
.
objectsDiffs
(
previousData
,
_data
);
[
"
updated
"
,
"
deleted
"
,
"
added
"
].
forEach
(
function
(
value
)
{
diffs
[
value
].
forEach
(
function
(
dataIndex
)
{
_storeObservable
.
notify
(
value
,
dataIndex
,
_data
[
dataIndex
]);
_valueObservable
.
notify
(
dataIndex
,
_data
[
dataIndex
],
value
);
});
});
};
/**
/**
* Get the number of items in the store
* Saves the handles for the subscriptions of the computed properties
* @returns {Number} the number of items in the store
* @private
*/
*/
this
.
getNbItems
=
function
()
{
_computed
=
[],
return
_data
instanceof
Array
?
_data
.
length
:
Tools
.
count
(
_data
);
};
/**
/**
* Count is an alias for getNbItems
* Gets the difference between two objects and notifies them
* @returns {Number} the number of items in the store
* @private
*/
* @param {Object} previousData
this
.
count
=
this
.
getNbItems
;
*/
_notifyDiffs
=
function
_notifyDiffs
(
previousData
)
{
var
diffs
=
Tools
.
objectsDiffs
(
previousData
,
_data
);
[
"
updated
"
,
"
deleted
"
,
"
added
"
].
forEach
(
function
(
value
)
{
diffs
[
value
].
forEach
(
function
(
dataIndex
)
{
_storeObservable
.
notify
(
value
,
dataIndex
,
_data
[
dataIndex
]);
_valueObservable
.
notify
(
dataIndex
,
_data
[
dataIndex
],
value
);
});
});
};
/**
/**
* Get a value from its index
* Get the number of items in the store
* @param {String} name the name of the index
* @returns {Number} the number of items in the store
* @returns the value
*/
*/
this
.
getNbItems
=
function
()
{
this
.
get
=
function
get
(
name
)
{
return
_data
instanceof
Array
?
_data
.
length
:
Tools
.
count
(
_data
);
return
_data
[
name
];
};
};
/**
/**
* Checks if the store has a given value
* Count is an alias for getNbItems
* @param {String} name the name of the index
* @returns {Number} the number of items in the store
* @returns {Boolean} true if the value exists
*/
*/
this
.
count
=
this
.
getNbItems
;
this
.
has
=
function
has
(
name
)
{
return
_data
.
hasOwnProperty
(
name
);
};
/**
/**
* Set a new value and overrides an existing one
* Get a value from its index
* @param {String} name the name of the index
* @param {String} name the name of the index
* @param value the value to assign
* @returns the value
* @returns true if value is set
*/
*/
this
.
get
=
function
get
(
name
)
{
this
.
set
=
function
set
(
name
,
value
)
{
return
_data
[
name
];
var
hasPrevious
,
};
previousValue
,
action
;
if
(
typeof
name
!=
"
undefined
"
)
{
hasPrevious
=
this
.
has
(
name
);
previousValue
=
this
.
get
(
name
);
_data
[
name
]
=
value
;
action
=
hasPrevious
?
"
updated
"
:
"
added
"
;
_storeObservable
.
notify
(
action
,
name
,
_data
[
name
],
previousValue
);
_valueObservable
.
notify
(
name
,
_data
[
name
],
action
,
previousValue
);
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Update the property of an item.
* Checks if the store has a given value
* @param {String} name the name of the index
* @param {String} name the name of the index
* @param {String} property the property to modify.
* @returns {Boolean} true if the value exists
* @param value the value to assign
*/
* @returns false if the Store has no name index
this
.
has
=
function
has
(
name
)
{
*/
return
_data
.
hasOwnProperty
(
name
);
this
.
update
=
function
update
(
name
,
property
,
value
)
{
};
var
item
;
if
(
this
.
has
(
name
))
{
item
=
this
.
get
(
name
);
Tools
.
setNestedProperty
(
item
,
property
,
value
);
_storeObservable
.
notify
(
"
updated
"
,
property
,
value
);
_valueObservable
.
notify
(
name
,
item
,
"
updated
"
);
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Delete value from its index
* Set a new value and overrides an existing one
* @param {String} name the name of the index from which to delete the value
* @param {String} name the name of the index
* @returns true if successfully deleted.
* @param value the value to assign
*/
* @returns true if value is set
this
.
del
=
function
del
(
name
)
{
*/
if
(
this
.
has
(
name
))
{
this
.
set
=
function
set
(
name
,
value
)
{
if
(
!
this
.
alter
(
"
splice
"
,
name
,
1
))
{
var
hasPrevious
,
delete
_data
[
name
];
previousValue
,
_storeObservable
.
notify
(
"
deleted
"
,
name
);
action
;
_valueObservable
.
notify
(
name
,
_data
[
name
],
"
deleted
"
);
}
if
(
typeof
name
!=
"
undefined
"
)
{
return
true
;
hasPrevious
=
this
.
has
(
name
);
}
else
{
previousValue
=
this
.
get
(
name
);
return
false
;
_data
[
name
]
=
value
;
}
action
=
hasPrevious
?
"
updated
"
:
"
added
"
;
};
_storeObservable
.
notify
(
action
,
name
,
_data
[
name
],
previousValue
);
_valueObservable
.
notify
(
name
,
_data
[
name
],
action
,
previousValue
);
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Delete multiple indexes. Prefer this one over multiple del calls.
* Update the property of an item.
* @param {Array}
* @param {String} name the name of the index
* @returns false if param is not an array.
* @param {String} property the property to modify.
*/
* @param value the value to assign
this
.
delAll
=
function
delAll
(
indexes
)
{
* @returns false if the Store has no name index
if
(
indexes
instanceof
Array
)
{
*/
// Indexes must be removed from the greatest to the lowest
this
.
update
=
function
update
(
name
,
property
,
value
)
{
// To avoid trying to remove indexes that don't exist.
var
item
;
// i.e: given [0, 1, 2], remove 1, then 2, 2 doesn't exist anymore
if
(
this
.
has
(
name
))
{
indexes
.
sort
(
Tools
.
compareNumbers
)
item
=
this
.
get
(
name
);
.
reverse
()
Tools
.
setNestedProperty
(
item
,
property
,
value
);
.
forEach
(
this
.
del
,
this
);
_storeObservable
.
notify
(
"
updated
"
,
property
,
value
);
return
true
;
_valueObservable
.
notify
(
name
,
item
,
"
updated
"
);
}
else
{
return
true
;
return
false
;
}
else
{
}
return
false
;
};
}
};
/**
/**
* Alter the data be calling one of it's method
* Delete value from its index
* When the modifications are done, it notifies on changes.
* @param {String} name the name of the index from which to delete the value
* @param {String} func the name of the method
* @returns true if successfully deleted.
* @returns the result of the method call
*/
*/
this
.
del
=
function
del
(
name
)
{
this
.
alter
=
function
alter
(
func
)
{
if
(
this
.
has
(
name
))
{
var
apply
,
if
(
!
this
.
alter
(
"
splice
"
,
name
,
1
))
{
previousData
;
delete
_data
[
name
];
_storeObservable
.
notify
(
"
deleted
"
,
name
);
if
(
_data
[
func
])
{
_valueObservable
.
notify
(
name
,
_data
[
name
],
"
deleted
"
);
previousData
=
Tools
.
clone
(
_data
);
}
apply
=
_data
[
func
].
apply
(
_data
,
Array
.
prototype
.
slice
.
call
(
arguments
,
1
));
return
true
;
_notifyDiffs
(
previousData
);
}
else
{
return
apply
;
return
false
;
}
else
{
}
return
false
;
};
}
};
/**
/**
* proxy is an alias for alter
* Delete multiple indexes. Prefer this one over multiple del calls.
*/
* @param {Array}
this
.
proxy
=
this
.
alter
;
* @returns false if param is not an array.
*/
this
.
delAll
=
function
delAll
(
indexes
)
{
if
(
indexes
instanceof
Array
)
{
// Indexes must be removed from the greatest to the lowest
// To avoid trying to remove indexes that don't exist.
// i.e: given [0, 1, 2], remove 1, then 2, 2 doesn't exist anymore
indexes
.
sort
(
Tools
.
compareNumbers
)
.
reverse
()
.
forEach
(
this
.
del
,
this
);
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Watch the store's modifications
* Alter the data by calling one of it's method
* @param {String} added/updated/deleted
* When the modifications are done, it notifies on changes.
* @param {Function} func the function to execute
* If the function called doesn't alter the data, consider using proxy instead
* @param {Object} scope the scope in which to execute the function
* which is much, much faster.
* @returns {Handle} the subscribe's handler to use to stop watching
* @param {String} func the name of the method
*/
* @params {*} any number of params to be given to the func
this
.
watch
=
function
watch
(
name
,
func
,
scope
)
{
* @returns the result of the method call
return
_storeObservable
.
watch
(
name
,
func
,
scope
);
*/
};
this
.
alter
=
function
alter
(
func
)
{
var
apply
,
previousData
;
if
(
_data
[
func
])
{
previousData
=
Tools
.
clone
(
_data
);
apply
=
this
.
proxy
.
apply
(
this
,
arguments
);
_notifyDiffs
(
previousData
);
_storeObservable
.
notify
(
"
altered
"
,
_data
,
previousData
);
return
apply
;
}
else
{
return
false
;
}
};
/**
/**
* Unwatch the store modifications
* Proxy is similar to alter but doesn't trigger events.
* @param {Handle} handle the handler returned by the watch function
* It's preferable to call proxy for functions that don't
* @returns
* update the interal data source, like slice or filter.
*/
* @param {String} func the name of the method
this
.
unwatch
=
function
unwatch
(
handle
)
{
* @params {*} any number of params to be given to the func
return
_storeObservable
.
unwatch
(
handle
);
* @returns the result of the method call
};
*/
this
.
proxy
=
function
proxy
(
func
)
{
if
(
_data
[
func
])
{
return
_data
[
func
].
apply
(
_data
,
Array
.
prototype
.
slice
.
call
(
arguments
,
1
));
}
else
{
return
false
;
}
};
/**
/**
* Get the observable used for watching store's modifications
* Watch the store's modifications
* Should be used only for debugging
* @param {String} added/updated/deleted
* @returns {Observable} the Observable
* @param {Function} func the function to execute
*/
* @param {Object} scope the scope in which to execute the function
this
.
getStoreObservable
=
function
getStoreObservable
()
{
* @returns {Handle} the subscribe's handler to use to stop watching
return
_storeObservable
;
*/
};
this
.
watch
=
function
watch
(
name
,
func
,
scope
)
{
return
_storeObservable
.
watch
(
name
,
func
,
scope
);
};
/**
/**
* Watch a value's modifications
* Unwatch the store modifications
* @param {String} name the name of the value to watch for
* @param {Handle} handle the handler returned by the watch function
* @param {Function} func the function to execute
* @returns
* @param {Object} scope the scope in which to execute the function
*/
* @returns handler to pass to unwatchValue
this
.
unwatch
=
function
unwatch
(
handle
)
{
*/
return
_storeObservable
.
unwatch
(
handle
);
this
.
watchValue
=
function
watchValue
(
name
,
func
,
scope
)
{
};
return
_valueObservable
.
watch
(
name
,
func
,
scope
);
};
/**
/**
* Unwatch the value's modifications
* Get the observable used for watching store's modifications
* @param {Handler} handler the handler returned by the watchValue function
* Should be used only for debugging
* @private
* @returns {Observable} the Observable
* @returns true if unwatched
*/
*/
this
.
getStoreObservable
=
function
getStoreObservable
()
{
this
.
unwatchValue
=
function
unwatchValue
(
handler
)
{
return
_storeObservable
;
return
_valueObservable
.
unwatch
(
handler
);
};
};
/**
/**
* Get the observable used for watching value's modifications
* Watch a value's modifications
* Should be used only for debugging
* @param {String} name the name of the value to watch for
* @private
* @param {Function} func the function to execute
* @returns {Observable} the Observable
* @param {Object} scope the scope in which to execute the function
*/
* @returns handler to pass to unwatchValue
this
.
getValueObservable
=
function
getValueObservable
()
{
*/
return
_valueObservable
;
this
.
watchValue
=
function
watchValue
(
name
,
func
,
scope
)
{
};
return
_valueObservable
.
watch
(
name
,
func
,
scope
);
};
/**
/**
* Loop through the data
* Unwatch the value's modifications
* @param {Function} func the function to execute on each data
* @param {Handler} handler the handler returned by the watchValue function
* @param {Object} scope the scope in wich to run the callback
* @private
*/
* @returns true if unwatched
this
.
loop
=
function
loop
(
func
,
scope
)
{
*/
Tools
.
loop
(
_data
,
func
,
scope
);
this
.
unwatchValue
=
function
unwatchValue
(
handler
)
{
};
return
_valueObservable
.
unwatch
(
handler
);
};
/**
/**
* Reset all data and get notifications on changes
* Get the observable used for watching value's modifications
* @param {Arra/Object} data the new data
* Should be used only for debugging
* @returns {Boolean}
* @private
*/
* @returns {Observable} the Observable
this
.
reset
=
function
reset
(
data
)
{
*/
if
(
data
instanceof
Object
)
{
this
.
getValueObservable
=
function
getValueObservable
()
{
var
previousData
=
Tools
.
clone
(
_data
);
return
_valueObservable
;
_data
=
Tools
.
clone
(
data
)
||
{};
};
_notifyDiffs
(
previousData
);
return
true
;
}
else
{
return
false
;
}
};
/**
* Loop through the data
* @param {Function} func the function to execute on each data
* @param {Object} scope the scope in wich to run the callback
*/
this
.
loop
=
function
loop
(
func
,
scope
)
{
Tools
.
loop
(
_data
,
func
,
scope
);
};
/**
/**
* Returns a JSON version of the data
* Reset all data and get notifications on changes
* Use dump if you want all the data as a plain js object
* @param {Arra/Object} data the new data
* @returns {String} the JSON
* @returns {Boolean}
*/
*/
this
.
toJSON
=
function
toJSON
()
{
this
.
reset
=
function
reset
(
data
)
{
return
JSON
.
stringify
(
_data
);
if
(
data
instanceof
Object
)
{
};
var
previousData
=
Tools
.
clone
(
_data
);
_data
=
Tools
.
clone
(
data
)
||
{};
_notifyDiffs
(
previousData
);
_storeObservable
.
notify
(
"
resetted
"
,
_data
,
previousData
);
return
true
;
}
else
{
return
false
;
}
/**
};
* Returns the store's data
* @returns {Object} the data
/**
*/
* Compute a new property from other properties.
this
.
dump
=
function
dump
()
{
* The computed property will look exactly similar to any none
return
_data
;
* computed property, it can be watched upon.
};
* @param {String} name the name of the computed property
};
* @param {Array} computeFrom a list of properties to compute from
* @param {Function} callback the callback to compute the property
* @param {Object} scope the scope in which to execute the callback
* @returns {Boolean} false if wrong params given to the function
*/
this
.
compute
=
function
compute
(
name
,
computeFrom
,
callback
,
scope
)
{
var
args
=
[];
if
(
typeof
name
==
"
string
"
&&
typeof
computeFrom
==
"
object
"
&&
typeof
callback
==
"
function
"
&&
!
this
.
isCompute
(
name
))
{
_computed
[
name
]
=
[];
Tools
.
loop
(
computeFrom
,
function
(
property
)
{
_computed
[
name
].
push
(
this
.
watchValue
(
property
,
function
()
{
this
.
set
(
name
,
callback
.
call
(
scope
));
},
this
));
},
this
);
this
.
set
(
name
,
callback
.
call
(
scope
));
return
true
;
}
else
{
return
false
;
}
};
/**
* Remove a computed property
* @param {String} name the name of the computed to remove
* @returns {Boolean} true if the property is removed
*/
this
.
removeCompute
=
function
removeCompute
(
name
)
{
if
(
this
.
isCompute
(
name
))
{
Tools
.
loop
(
_computed
[
name
],
function
(
handle
)
{
this
.
unwatchValue
(
handle
);
},
this
);
this
.
del
(
name
);
return
true
;
}
else
{
return
false
;
}
};
/**
* Tells if a property is a computed property
* @param {String} name the name of the property to test
* @returns {Boolean} true if it's a computed property
*/
this
.
isCompute
=
function
isCompute
(
name
)
{
return
!!
_computed
[
name
];
};
/**
* Returns a JSON version of the data
* Use dump if you want all the data as a plain js object
* @returns {String} the JSON
*/
this
.
toJSON
=
function
toJSON
()
{
return
JSON
.
stringify
(
_data
);
};
/**
* Returns the store's data
* @returns {Object} the data
*/
this
.
dump
=
function
dump
()
{
return
_data
;
};
};
});
});
/**
/**
* Emily
* Emily
.js - http://flams.github.com/emily/
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* MIT Licensed
* MIT Licensed
*/
*/
define
(
'
Transport
'
,[],
define
(
'
Transport
'
,[],
/**
/**
* @class
* @class
...
@@ -1275,96 +1450,339 @@ define('Transport',[],
...
@@ -1275,96 +1450,339 @@ define('Transport',[],
*/
*/
function
Transport
()
{
function
Transport
()
{
/**
* Create a Transport
* @param {Emily Store} [optionanl] $reqHandlers an object containing the request handlers
* @returns
*/
return
function
TransportConstructor
(
$reqHandlers
)
{
/**
/**
* The request handlers
* Create a Transport
* @private
* @param {Emily Store} [optionanl] $reqHandlers an object containing the request handlers
*/
* @returns
var
_reqHandlers
=
null
;
*/
return
function
TransportConstructor
(
$reqHandlers
)
{
/**
/**
* Set the requests handlers object
* The request handlers
* @param {Emily Store} reqHandlers an object containing the requests handlers
* @private
* @returns
*/
*/
var
_reqHandlers
=
null
;
this
.
setReqHandlers
=
function
setReqHandlers
(
reqHandlers
)
{
if
(
reqHandlers
instanceof
Object
)
{
_reqHandlers
=
reqHandlers
;
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Get the requests handlers
* Set the requests handlers object
* @returns{ Emily Store} reqHandlers the object containing the requests handlers
* @param {Emily Store} reqHandlers an object containing the requests handlers
*/
* @returns
this
.
getReqHandlers
=
function
getReqHandlers
()
{
*/
return
_reqHandlers
;
this
.
setReqHandlers
=
function
setReqHandlers
(
reqHandlers
)
{
};
if
(
reqHandlers
instanceof
Object
)
{
_reqHandlers
=
reqHandlers
;
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Issue a request to a request handler
* Get the requests handlers
* @param {String} reqHandler the name of the request handler to issue the request to
* @returns{ Emily Store} reqHandlers the object containing the requests handlers
* @param {Object} data the data, or payload, to send to the request handler
*/
* @param {Function} callback the function to execute with the result
this
.
getReqHandlers
=
function
getReqHandlers
()
{
* @param {Object} scope the scope in which to execute the callback
return
_reqHandlers
;
* @returns
};
*/
this
.
request
=
function
request
(
reqHandler
,
data
,
callback
,
scope
)
{
if
(
_reqHandlers
.
has
(
reqHandler
)
&&
typeof
data
!=
"
undefined
"
)
{
_reqHandlers
.
get
(
reqHandler
)(
data
,
function
()
{
/**
callback
&&
callback
.
apply
(
scope
,
arguments
);
* Issue a request to a request handler
});
* @param {String} reqHandler the name of the request handler to issue the request to
return
true
;
* @param {Object} data the data, or payload, to send to the request handler
}
else
{
* @param {Function} callback the function to execute with the result
return
false
;
* @param {Object} scope the scope in which to execute the callback
}
* @returns
};
*/
this
.
request
=
function
request
(
reqHandler
,
data
,
callback
,
scope
)
{
if
(
_reqHandlers
.
has
(
reqHandler
)
&&
typeof
data
!=
"
undefined
"
)
{
_reqHandlers
.
get
(
reqHandler
)(
data
,
function
()
{
if
(
callback
)
{
callback
.
apply
(
scope
,
arguments
);
}
});
return
true
;
}
else
{
return
false
;
}
};
/**
/**
* Issue a request to a reqHandler but keep listening for the response as it can be sent in several chunks
* Issue a request to a reqHandler but keep listening for the response as it can be sent in several chunks
* or remain open as long as the abort funciton is not called
* or remain open as long as the abort funciton is not called
* @param {String} reqHandler the name of the request handler to issue the request to
* @param {String} reqHandler the name of the request handler to issue the request to
* @param {Object} data the data, or payload, to send to the request handler
* @param {Object} data the data, or payload, to send to the request handler
* @param {Function} callback the function to execute with the result
* @param {Function} callback the function to execute with the result
* @param {Object} scope the scope in which to execute the callback
* @param {Object} scope the scope in which to execute the callback
* @returns {Function} the abort function to call to stop listening
* @returns {Function} the abort function to call to stop listening
*/
*/
this
.
listen
=
function
listen
(
reqHandler
,
data
,
callback
,
scope
)
{
this
.
listen
=
function
listen
(
reqHandler
,
data
,
callback
,
scope
)
{
if
(
_reqHandlers
.
has
(
reqHandler
)
if
(
_reqHandlers
.
has
(
reqHandler
)
&&
&&
typeof
data
!=
"
undefined
"
typeof
data
!=
"
undefined
"
&&
&&
typeof
callback
==
"
function
"
)
{
typeof
callback
==
"
function
"
)
{
var
func
=
function
()
{
var
func
=
function
()
{
callback
.
apply
(
scope
,
arguments
);
callback
.
apply
(
scope
,
arguments
);
},
},
abort
;
abort
;
abort
=
_reqHandlers
.
get
(
reqHandler
)(
data
,
func
,
func
);
abort
=
_reqHandlers
.
get
(
reqHandler
)(
data
,
func
,
func
);
return
function
()
{
return
function
()
{
if
(
typeof
abort
==
"
function
"
)
{
if
(
typeof
abort
==
"
function
"
)
{
abort
();
abort
();
}
else
if
(
typeof
abort
==
"
object
"
&&
typeof
abort
.
func
==
"
function
"
)
{
}
else
if
(
typeof
abort
==
"
object
"
&&
typeof
abort
.
func
==
"
function
"
)
{
abort
.
func
.
call
(
abort
.
scope
);
abort
.
func
.
call
(
abort
.
scope
);
}
}
};
};
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
this
.
setReqHandlers
(
$reqHandlers
);
this
.
setReqHandlers
(
$reqHandlers
);
};
};
});
});
/**
* Emily.js - http://flams.github.com/emily/
* Copyright(c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com>
* MIT Licensed
*/
define
(
'
Router
'
,[
"
Observable
"
,
"
Store
"
,
"
Tools
"
],
/**
* @class
* Routing allows for navigating in an application by defining routes.
*/
function
Router
(
Observable
,
Store
,
Tools
)
{
return
function
RouterConstructor
()
{
/**
* The routes observable (the applications use it)
* @private
*/
var
_routes
=
new
Observable
(),
/**
* The events observable (used by Routing)
* @private
*/
_events
=
new
Observable
(),
/**
* The routing history
* @private
*/
_history
=
new
Store
([]),
/**
* For navigating through the history, remembers the current position
* @private
*/
_currentPos
=
-
1
,
/**
* The depth of the history
* @private
*/
_maxHistory
=
10
;
/**
* Only for debugging
* @private
*/
this
.
getRoutesObservable
=
function
getRoutesObservable
()
{
return
_routes
;
};
/**
* Only for debugging
* @private
*/
this
.
getEventsObservable
=
function
getEventsObservable
()
{
return
_events
;
};
/**
* Set the maximum length of history
* As the user navigates through the application, the
* routeur keeps track of the history. Set the depth of the history
* depending on your need and the amount of memory that you can allocate it
* @param {Number} maxHistory the depth of history
* @returns {Boolean} true if maxHistory is equal or greater than 0
*/
this
.
setMaxHistory
=
function
setMaxHistory
(
maxHistory
)
{
if
(
maxHistory
>=
0
)
{
_maxHistory
=
maxHistory
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Get the current max history setting
* @returns {Number} the depth of history
*/
this
.
getMaxHistory
=
function
getMaxHistory
()
{
return
_maxHistory
;
};
/**
* Set a new route
* @param {String} route the name of the route
* @param {Function} func the function to be execute when navigating to the route
* @param {Object} scope the scope in which to execute the function
* @returns a handle to remove the route
*/
this
.
set
=
function
set
()
{
return
_routes
.
watch
.
apply
(
_routes
,
arguments
);
};
/**
* Remove a route
* @param {Object} handle the handle provided by the set method
* @returns true if successfully removed
*/
this
.
unset
=
function
unset
(
handle
)
{
return
_routes
.
unwatch
(
handle
);
};
/**
* Navigate to a route
* @param {String} route the route to navigate to
* @param {*} *params
* @returns
*/
this
.
navigate
=
function
get
(
route
,
params
)
{
if
(
this
.
load
.
apply
(
this
,
arguments
))
{
// Before adding a new route to the history, we must clear the forward history
_history
.
proxy
(
"
splice
"
,
_currentPos
+
1
,
_history
.
count
());
_history
.
proxy
(
"
push
"
,
Tools
.
toArray
(
arguments
));
this
.
ensureMaxHistory
(
_history
);
_currentPos
=
_history
.
count
()
-
1
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Ensure that history doesn't grow bigger than the max history setting
* @param {Store} history the history store
* @private
*/
this
.
ensureMaxHistory
=
function
ensureMaxHistory
(
history
)
{
var
count
=
history
.
count
(),
max
=
this
.
getMaxHistory
(),
excess
=
count
-
max
;
if
(
excess
>
0
)
{
history
.
proxy
(
"
splice
"
,
0
,
excess
);
}
};
/**
* Actually loads the route
* @private
*/
this
.
load
=
function
load
()
{
var
copy
=
Tools
.
toArray
(
arguments
);
if
(
_routes
.
notify
.
apply
(
_routes
,
copy
))
{
copy
.
unshift
(
"
route
"
);
_events
.
notify
.
apply
(
_events
,
copy
);
return
true
;
}
else
{
return
false
;
}
};
/**
* Watch for route changes
* @param {Function} func the func to execute when the route changes
* @param {Object} scope the scope in which to execute the function
* @returns {Object} the handle to unwatch for route changes
*/
this
.
watch
=
function
watch
(
func
,
scope
)
{
return
_events
.
watch
(
"
route
"
,
func
,
scope
);
};
/**
* Unwatch routes changes
* @param {Object} handle the handle was returned by the watch function
* @returns true if unwatch
*/
this
.
unwatch
=
function
unwatch
(
handle
)
{
return
_events
.
unwatch
(
handle
);
};
/**
* Get the history store, for debugging only
* @private
*/
this
.
getHistoryStore
=
function
getHistoryStore
()
{
return
_history
;
};
/**
* Get the current length of history
* @returns {Number} the length of history
*/
this
.
getHistoryCount
=
function
getHistoryCount
()
{
return
_history
.
count
();
};
/**
* Flush the entire history
*/
this
.
clearHistory
=
function
clearHistory
()
{
_history
.
reset
([]);
};
/**
* Go back and forth in the history
* @param {Number} nb the amount of history to rewind/forward
* @returns true if history exists
*/
this
.
go
=
function
go
(
nb
)
{
var
history
=
_history
.
get
(
_currentPos
+
nb
);
if
(
history
)
{
_currentPos
+=
nb
;
this
.
load
.
apply
(
this
,
history
);
return
true
;
}
else
{
return
false
;
}
};
/**
* Go back in the history, short for go(-1)
* @returns
*/
this
.
back
=
function
back
()
{
return
this
.
go
(
-
1
);
};
/**
* Go forward in the history, short for go(1)
* @returns
*/
this
.
forward
=
function
forward
()
{
return
this
.
go
(
1
);
};
};
});
\ No newline at end of file
examples/olives/bower_components/olives/build/Olives.js
View file @
9df98e41
...
@@ -12,6 +12,8 @@
...
@@ -12,6 +12,8 @@
define
(
'
DomUtils
'
,[
"
Tools
"
],
function
(
Tools
)
{
define
(
'
DomUtils
'
,[
"
Tools
"
],
function
(
Tools
)
{
return
{
return
{
/**
/**
* Returns a NodeList including the given dom node,
* Returns a NodeList including the given dom node,
...
@@ -127,375 +129,406 @@ define('Bind.plugin',["Store", "Observable", "Tools", "DomUtils"],
...
@@ -127,375 +129,406 @@ define('Bind.plugin',["Store", "Observable", "Tools", "DomUtils"],
*/
*/
function
BindPlugin
(
Store
,
Observable
,
Tools
,
DomUtils
)
{
function
BindPlugin
(
Store
,
Observable
,
Tools
,
DomUtils
)
{
return
function
BindPluginConstructor
(
$model
,
$bindings
)
{
/**
return
function
BindPluginConstructor
(
$model
,
$bindings
)
{
* The model to watch
* @private
/**
*/
* The model to watch
var
_model
=
null
,
* @private
*/
/**
var
_model
=
null
,
* The list of custom bindings
* @private
/**
*/
* The list of custom bindings
_bindings
=
{},
* @private
*/
/**
_bindings
=
{},
* The list of itemRenderers
* each foreach has its itemRenderer
/**
* @private
* The list of itemRenderers
*/
* each foreach has its itemRenderer
_itemRenderers
=
{};
* @private
*/
/**
_itemRenderers
=
{},
* The observers handlers
* for debugging only
/**
* @private
* The observers handlers
*/
* @private
this
.
observers
=
{};
*/
_observers
=
{};
/**
* Define the model to watch for
/**
* @param {Store} model the model to watch for changes
* Exposed for debugging purpose
* @returns {Boolean} true if the model was set
* @private
*/
*/
this
.
setModel
=
function
setModel
(
model
)
{
this
.
observers
=
_observers
;
if
(
model
instanceof
Store
)
{
// Set the model
function
_removeObserversForId
(
id
)
{
_model
=
model
;
if
(
_observers
[
id
])
{
return
true
;
_observers
[
id
].
forEach
(
function
(
handler
)
{
}
else
{
_model
.
unwatchValue
(
handler
);
return
false
;
});
}
delete
_observers
[
id
];
};
}
}
/**
* Get the store that is watched for
/**
* for debugging only
* Define the model to watch for
* @private
* @param {Store} model the model to watch for changes
* @returns the Store
* @returns {Boolean} true if the model was set
*/
*/
this
.
getModel
=
function
getModel
()
{
this
.
setModel
=
function
setModel
(
model
)
{
return
_model
;
if
(
model
instanceof
Store
)
{
};
// Set the model
_model
=
model
;
/**
return
true
;
* The item renderer defines a dom node that can be duplicated
}
else
{
* It is made available for debugging purpose, don't use it
return
false
;
* @private
}
*/
};
this
.
ItemRenderer
=
function
ItemRenderer
(
$plugins
,
$rootNode
)
{
/**
/**
* Get the store that is watched for
* The node that will be cloned
* for debugging only
* @private
* @private
*/
* @returns the Store
var
_node
=
null
,
*/
this
.
getModel
=
function
getModel
()
{
/**
return
_model
;
* The object that contains plugins.name and plugins.apply
};
* @private
*/
/**
_plugins
=
null
,
* The item renderer defines a dom node that can be duplicated
* It is made available for debugging purpose, don't use it
/**
* @private
* The _rootNode where to append the created items
*/
* @private
this
.
ItemRenderer
=
function
ItemRenderer
(
$plugins
,
$rootNode
)
{
*/
_rootNode
=
null
,
/**
* The node that will be cloned
/**
* @private
* The lower boundary
*/
* @private
var
_node
=
null
,
*/
_start
=
null
,
/**
* The object that contains plugins.name and plugins.apply
/**
* @private
* The number of item to display
*/
* @private
_plugins
=
null
,
*/
_nb
=
null
;
/**
* The _rootNode where to append the created items
/**
* @private
* Set the duplicated node
*/
* @private
_rootNode
=
null
,
*/
this
.
setRenderer
=
function
setRenderer
(
node
)
{
/**
_node
=
node
;
* The lower boundary
return
true
;
* @private
};
*/
_start
=
null
,
/**
* Returns the node that is going to be used for rendering
/**
* @private
* The number of item to display
* @returns the node that is duplicated
* @private
*/
*/
this
.
getRenderer
=
function
getRenderer
()
{
_nb
=
null
;
return
_node
;
};
/**
* Set the duplicated node
/**
* @private
* Sets the rootNode and gets the node to copy
*/
* @private
this
.
setRenderer
=
function
setRenderer
(
node
)
{
* @param {HTMLElement|SVGElement} rootNode
_node
=
node
;
* @returns
return
true
;
*/
};
this
.
setRootNode
=
function
setRootNode
(
rootNode
)
{
var
renderer
;
/**
if
(
DomUtils
.
isAcceptedType
(
rootNode
))
{
* Returns the node that is going to be used for rendering
_rootNode
=
rootNode
;
* @private
renderer
=
_rootNode
.
querySelector
(
"
*
"
);
* @returns the node that is duplicated
this
.
setRenderer
(
renderer
);
*/
renderer
&&
_rootNode
.
removeChild
(
renderer
);
this
.
getRenderer
=
function
getRenderer
()
{
return
true
;
return
_node
;
}
else
{
};
return
false
;
}
/**
};
* Sets the rootNode and gets the node to copy
* @private
/**
* @param {HTMLElement|SVGElement} rootNode
* Gets the rootNode
* @returns
* @private
*/
* @returns _rootNode
this
.
setRootNode
=
function
setRootNode
(
rootNode
)
{
*/
var
renderer
;
this
.
getRootNode
=
function
getRootNode
()
{
if
(
DomUtils
.
isAcceptedType
(
rootNode
))
{
return
_rootNode
;
_rootNode
=
rootNode
;
};
renderer
=
_rootNode
.
querySelector
(
"
*
"
);
this
.
setRenderer
(
renderer
);
/**
if
(
renderer
)
{
* Set the plugins objet that contains the name and the apply function
_rootNode
.
removeChild
(
renderer
);
* @private
}
* @param plugins
return
true
;
* @returns true
}
else
{
*/
return
false
;
this
.
setPlugins
=
function
setPlugins
(
plugins
)
{
}
_plugins
=
plugins
;
};
return
true
;
};
/**
* Gets the rootNode
/**
* @private
* Get the plugins object
* @returns _rootNode
* @private
*/
* @returns the plugins object
this
.
getRootNode
=
function
getRootNode
()
{
*/
return
_rootNode
;
this
.
getPlugins
=
function
getPlugins
()
{
};
return
_plugins
;
};
/**
* Set the plugins objet that contains the name and the apply function
/**
* @private
* The nodes created from the items are stored here
* @param plugins
* @private
* @returns true
*/
*/
this
.
items
=
new
Store
([]);
this
.
setPlugins
=
function
setPlugins
(
plugins
)
{
_plugins
=
plugins
;
/**
return
true
;
* Set the start limit
};
* @private
* @param {Number} start the value to start rendering the items from
/**
* @returns the value
* Get the plugins object
*/
* @private
this
.
setStart
=
function
setStart
(
start
)
{
* @returns the plugins object
return
_start
=
parseInt
(
start
,
10
);
*/
};
this
.
getPlugins
=
function
getPlugins
()
{
return
_plugins
;
/**
};
* Get the start value
* @private
/**
* @returns the start value
* The nodes created from the items are stored here
*/
* @private
this
.
getStart
=
function
getStart
()
{
*/
return
_start
;
this
.
items
=
{};
};
/**
/**
* Set the start limit
* Set the number of item to display
* @private
* @private
* @param {Number} start the value to start rendering the items from
* @param {Number/String} nb the number of item to display or "*" for all
* @returns the value
* @returns the value
*/
*/
this
.
setStart
=
function
setStart
(
start
)
{
this
.
setNb
=
function
setNb
(
nb
)
{
_start
=
parseInt
(
start
,
10
);
return
_nb
=
nb
==
"
*
"
?
nb
:
parseInt
(
nb
,
10
);
return
_start
;
};
};
/**
/**
* Get the number of item to display
* Get the start value
* @private
* @private
* @returns the value
* @returns the start value
*/
*/
this
.
getNb
=
function
getNb
()
{
this
.
getStart
=
function
getStart
()
{
return
_nb
;
return
_start
;
};
};
/**
/**
* Adds a new item and adds it in the items list
* Set the number of item to display
* @private
* @private
* @param {Number} id the id of the item
* @param {Number/String} nb the number of item to display or "*" for all
* @returns
* @returns the value
*/
*/
this
.
addItem
=
function
addItem
(
id
)
{
this
.
setNb
=
function
setNb
(
nb
)
{
var
node
,
_nb
=
nb
==
"
*
"
?
nb
:
parseInt
(
nb
,
10
);
next
;
return
_nb
;
};
if
(
typeof
id
==
"
number
"
&&
!
this
.
items
.
get
(
id
))
{
node
=
this
.
create
(
id
);
/**
if
(
node
)
{
* Get the number of item to display
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
* @private
next
=
this
.
getNextItem
(
id
);
* @returns the value
next
?
_rootNode
.
insertBefore
(
node
,
next
)
:
_rootNode
.
appendChild
(
node
);
*/
return
true
;
this
.
getNb
=
function
getNb
()
{
}
else
{
return
_nb
;
return
false
;
};
}
}
else
{
/**
return
false
;
* Adds a new item and adds it in the items list
}
* @private
};
* @param {Number} id the id of the item
* @returns
/**
*/
* Get the next item in the item store given an id.
this
.
addItem
=
function
addItem
(
id
)
{
* @private
var
node
,
* @param {Number} id the id to start from
next
;
* @returns
*/
if
(
typeof
id
==
"
number
"
&&
!
this
.
items
[
id
])
{
this
.
getNextItem
=
function
getNextItem
(
id
)
{
next
=
this
.
getNextItem
(
id
);
return
this
.
items
.
alter
(
"
slice
"
,
id
+
1
).
filter
(
function
(
value
)
{
node
=
this
.
create
(
id
);
if
(
DomUtils
.
isAcceptedType
(
value
))
{
if
(
node
)
{
return
true
;
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
}
if
(
next
)
{
})[
0
];
_rootNode
.
insertBefore
(
node
,
next
);
};
}
else
{
_rootNode
.
appendChild
(
node
);
/**
}
* Remove an item from the dom and the items list
return
true
;
* @private
}
else
{
* @param {Number} id the id of the item to remove
return
false
;
* @returns
}
*/
}
else
{
this
.
removeItem
=
function
removeItem
(
id
)
{
return
false
;
var
item
=
this
.
items
.
get
(
id
);
}
if
(
item
)
{
};
_rootNode
.
removeChild
(
item
);
this
.
items
.
set
(
id
);
/**
return
true
;
* Get the next item in the item store given an id.
}
else
{
* @private
return
false
;
* @param {Number} id the id to start from
}
* @returns
};
*/
this
.
getNextItem
=
function
getNextItem
(
id
)
{
/**
var
keys
=
Object
.
keys
(
this
.
items
).
map
(
function
(
string
)
{
* create a new node. Actually makes a clone of the initial one
return
Number
(
string
);
* and adds pluginname_id to each node, then calls plugins.apply to apply all plugins
}),
* @private
closest
=
Tools
.
closestGreater
(
id
,
keys
),
* @param id
closestId
=
keys
[
closest
];
* @param pluginName
* @returns the associated node
// Only return if different
*/
if
(
closestId
!=
id
)
{
this
.
create
=
function
create
(
id
)
{
return
this
.
items
[
closestId
];
if
(
_model
.
has
(
id
))
{
}
else
{
var
newNode
=
_node
.
cloneNode
(
true
),
return
;
nodes
=
DomUtils
.
getNodes
(
newNode
);
}
};
Tools
.
toArray
(
nodes
).
forEach
(
function
(
child
)
{
child
.
setAttribute
(
"
data-
"
+
_plugins
.
name
+
"
_id
"
,
id
);
/**
});
* Remove an item from the dom and the items list
* @private
this
.
items
.
set
(
id
,
newNode
);
* @param {Number} id the id of the item to remove
_plugins
.
apply
(
newNode
);
* @returns
return
newNode
;
*/
}
this
.
removeItem
=
function
removeItem
(
id
)
{
};
var
item
=
this
.
items
[
id
];
if
(
item
)
{
/**
_rootNode
.
removeChild
(
item
);
* Renders the dom tree, adds nodes that are in the boundaries
delete
this
.
items
[
id
];
* and removes the others
_removeObserversForId
(
id
);
* @private
return
true
;
* @returns true boundaries are set
}
else
{
*/
return
false
;
this
.
render
=
function
render
()
{
}
// If the number of items to render is all (*)
};
// Then get the number of items
var
_tmpNb
=
_nb
==
"
*
"
?
_model
.
getNbItems
()
:
_nb
;
/**
* create a new node. Actually makes a clone of the initial one
// This will store the items to remove
* and adds pluginname_id to each node, then calls plugins.apply to apply all plugins
var
marked
=
[];
* @private
* @param id
// Render only if boundaries have been set
* @param pluginName
if
(
_nb
!==
null
&&
_start
!==
null
)
{
* @returns the associated node
*/
// Loop through the existing items
this
.
create
=
function
create
(
id
)
{
this
.
items
.
loop
(
function
(
value
,
idx
)
{
if
(
_model
.
has
(
id
))
{
// If an item is out of the boundary
var
newNode
=
_node
.
cloneNode
(
true
),
if
(
idx
<
_start
||
idx
>=
(
_start
+
_tmpNb
)
||
!
_model
.
has
(
idx
))
{
nodes
=
DomUtils
.
getNodes
(
newNode
);
// Mark it
marked
.
push
(
idx
);
Tools
.
toArray
(
nodes
).
forEach
(
function
(
child
)
{
}
child
.
setAttribute
(
"
data-
"
+
_plugins
.
name
+
"
_id
"
,
id
);
},
this
);
});
// Remove the marked item from the highest id to the lowest
this
.
items
[
id
]
=
newNode
;
// Doing this will avoid the id change during removal
_plugins
.
apply
(
newNode
);
// (removing id 2 will make id 3 becoming 2)
return
newNode
;
marked
.
sort
(
Tools
.
compareNumbers
).
reverse
().
forEach
(
this
.
removeItem
,
this
);
}
};
// Now that we have removed the old nodes
// Add the missing one
/**
for
(
var
i
=
_start
,
l
=
_tmpNb
+
_start
;
i
<
l
;
i
++
)
{
* Renders the dom tree, adds nodes that are in the boundaries
this
.
addItem
(
i
);
* and removes the others
}
* @private
return
true
;
* @returns true boundaries are set
}
else
{
*/
return
false
;
this
.
render
=
function
render
()
{
}
// If the number of items to render is all (*)
};
// Then get the number of items
var
_tmpNb
=
_nb
==
"
*
"
?
_model
.
getNbItems
()
:
_nb
;
this
.
setPlugins
(
$plugins
);
this
.
setRootNode
(
$rootNode
);
// This will store the items to remove
};
var
marked
=
[];
/**
// Render only if boundaries have been set
* Save an itemRenderer according to its id
if
(
_nb
!==
null
&&
_start
!==
null
)
{
* @private
* @param {String} id the id of the itemRenderer
// Loop through the existing items
* @param {ItemRenderer} itemRenderer an itemRenderer object
Tools
.
loop
(
this
.
items
,
function
(
value
,
idx
)
{
*/
// If an item is out of the boundary
this
.
setItemRenderer
=
function
setItemRenderer
(
id
,
itemRenderer
)
{
idx
=
Number
(
idx
);
id
=
id
||
"
default
"
;
_itemRenderers
[
id
]
=
itemRenderer
;
if
(
idx
<
_start
||
idx
>=
(
_start
+
_tmpNb
)
||
!
_model
.
has
(
idx
))
{
};
// Mark it
marked
.
push
(
idx
);
/**
}
* Get an itemRenderer
},
this
);
* @private
* @param {String} id the name of the itemRenderer
// Remove the marked item from the highest id to the lowest
* @returns the itemRenderer
// Doing this will avoid the id change during removal
*/
// (removing id 2 will make id 3 becoming 2)
this
.
getItemRenderer
=
function
getItemRenderer
(
id
)
{
marked
.
sort
(
Tools
.
compareNumbers
).
reverse
().
forEach
(
this
.
removeItem
,
this
);
return
_itemRenderers
[
id
];
};
// Now that we have removed the old nodes
// Add the missing one
/**
for
(
var
i
=
_start
,
l
=
_tmpNb
+
_start
;
i
<
l
;
i
++
)
{
* Expands the inner dom nodes of a given dom node, filling it with model's values
this
.
addItem
(
i
);
* @param {HTMLElement|SVGElement} node the dom node to apply foreach to
}
*/
return
true
;
this
.
foreach
=
function
foreach
(
node
,
idItemRenderer
,
start
,
nb
)
{
}
else
{
var
itemRenderer
=
new
this
.
ItemRenderer
(
this
.
plugins
,
node
);
return
false
;
}
itemRenderer
.
setStart
(
start
||
0
);
};
itemRenderer
.
setNb
(
nb
||
"
*
"
);
this
.
setPlugins
(
$plugins
);
itemRenderer
.
render
();
this
.
setRootNode
(
$rootNode
);
};
// Add the newly created item
/**
* Save an itemRenderer according to its id
* @private
* @param {String} id the id of the itemRenderer
* @param {ItemRenderer} itemRenderer an itemRenderer object
*/
this
.
setItemRenderer
=
function
setItemRenderer
(
id
,
itemRenderer
)
{
id
=
id
||
"
default
"
;
_itemRenderers
[
id
]
=
itemRenderer
;
};
/**
* Get an itemRenderer
* @private
* @param {String} id the name of the itemRenderer
* @returns the itemRenderer
*/
this
.
getItemRenderer
=
function
getItemRenderer
(
id
)
{
return
_itemRenderers
[
id
];
};
/**
* Expands the inner dom nodes of a given dom node, filling it with model's values
* @param {HTMLElement|SVGElement} node the dom node to apply foreach to
*/
this
.
foreach
=
function
foreach
(
node
,
idItemRenderer
,
start
,
nb
)
{
var
itemRenderer
=
new
this
.
ItemRenderer
(
this
.
plugins
,
node
);
itemRenderer
.
setStart
(
start
||
0
);
itemRenderer
.
setNb
(
nb
||
"
*
"
);
itemRenderer
.
render
();
// Add the newly created item
_model
.
watch
(
"
added
"
,
itemRenderer
.
render
,
itemRenderer
);
_model
.
watch
(
"
added
"
,
itemRenderer
.
render
,
itemRenderer
);
// If an item is deleted
// If an item is deleted
_model
.
watch
(
"
deleted
"
,
function
(
idx
)
{
_model
.
watch
(
"
deleted
"
,
function
(
idx
)
{
itemRenderer
.
render
();
itemRenderer
.
render
();
// Also remove all observers
// Also remove all observers
this
.
observers
[
idx
]
&&
this
.
observers
[
idx
].
forEach
(
function
(
handler
)
{
_removeObserversForId
(
idx
);
_model
.
unwatchValue
(
handler
);
},
this
);
delete
this
.
observers
[
idx
];
},
this
);
},
this
);
this
.
setItemRenderer
(
idItemRenderer
,
itemRenderer
);
this
.
setItemRenderer
(
idItemRenderer
,
itemRenderer
);
...
@@ -508,13 +541,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
...
@@ -508,13 +541,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
* @returns true if the foreach exists
* @returns true if the foreach exists
*/
*/
this
.
updateStart
=
function
updateStart
(
id
,
start
)
{
this
.
updateStart
=
function
updateStart
(
id
,
start
)
{
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
if
(
itemRenderer
)
{
if
(
itemRenderer
)
{
itemRenderer
.
setStart
(
start
);
itemRenderer
.
setStart
(
start
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
...
@@ -524,13 +557,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
...
@@ -524,13 +557,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
* @returns true if the foreach exists
* @returns true if the foreach exists
*/
*/
this
.
updateNb
=
function
updateNb
(
id
,
nb
)
{
this
.
updateNb
=
function
updateNb
(
id
,
nb
)
{
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
if
(
itemRenderer
)
{
if
(
itemRenderer
)
{
itemRenderer
.
setNb
(
nb
);
itemRenderer
.
setNb
(
nb
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
...
@@ -539,202 +572,202 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
...
@@ -539,202 +572,202 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
* @returns true if the foreach exists
* @returns true if the foreach exists
*/
*/
this
.
refresh
=
function
refresh
(
id
)
{
this
.
refresh
=
function
refresh
(
id
)
{
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
if
(
itemRenderer
)
{
if
(
itemRenderer
)
{
itemRenderer
.
render
();
itemRenderer
.
render
();
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Both ways binding between a dom node attributes and the model
* Both ways binding between a dom node attributes and the model
* @param {HTMLElement|SVGElement} node the dom node to apply the plugin to
* @param {HTMLElement|SVGElement} node the dom node to apply the plugin to
* @param {String} name the name of the property to look for in the model's value
* @param {String} name the name of the property to look for in the model's value
* @returns
* @returns
*/
*/
this
.
bind
=
function
bind
(
node
,
property
,
name
)
{
this
.
bind
=
function
bind
(
node
,
property
,
name
)
{
// Name can be unset if the value of a row is plain text
// Name can be unset if the value of a row is plain text
name
=
name
||
""
;
name
=
name
||
""
;
// In case of an array-like model the id is the index of the model's item to look for.
// In case of an array-like model the id is the index of the model's item to look for.
// The _id is added by the foreach function
// The _id is added by the foreach function
var
id
=
node
.
getAttribute
(
"
data-
"
+
this
.
plugins
.
name
+
"
_id
"
),
var
id
=
node
.
getAttribute
(
"
data-
"
+
this
.
plugins
.
name
+
"
_id
"
),
// Else, it is the first element of the following
// Else, it is the first element of the following
split
=
name
.
split
(
"
.
"
),
split
=
name
.
split
(
"
.
"
),
// So the index of the model is either id or the first element of split
// So the index of the model is either id or the first element of split
modelIdx
=
id
||
split
.
shift
(),
modelIdx
=
id
||
split
.
shift
(),
// And the name of the property to look for in the value is
// And the name of the property to look for in the value is
prop
=
id
?
name
:
split
.
join
(
"
.
"
),
prop
=
id
?
name
:
split
.
join
(
"
.
"
),
// Get the model's value
// Get the model's value
get
=
Tools
.
getNestedProperty
(
_model
.
get
(
modelIdx
),
prop
),
get
=
Tools
.
getNestedProperty
(
_model
.
get
(
modelIdx
),
prop
),
// When calling bind like bind:newBinding,param1, param2... we need to get them
// When calling bind like bind:newBinding,param1, param2... we need to get them
extraParam
=
Tools
.
toArray
(
arguments
).
slice
(
3
);
extraParam
=
Tools
.
toArray
(
arguments
).
slice
(
3
);
// 0 and false are acceptable falsy values
// 0 and false are acceptable falsy values
if
(
get
||
get
===
0
||
get
===
false
)
{
if
(
get
||
get
===
0
||
get
===
false
)
{
// If the binding hasn't been overriden
// If the binding hasn't been overriden
if
(
!
this
.
execBinding
.
apply
(
this
,
if
(
!
this
.
execBinding
.
apply
(
this
,
[
node
,
property
,
get
]
[
node
,
property
,
get
]
// Extra params are passed to the new binding too
// Extra params are passed to the new binding too
.
concat
(
extraParam
)))
{
.
concat
(
extraParam
)))
{
// Execute the default one which is a simple assignation
// Execute the default one which is a simple assignation
//node[property] = get;
//node[property] = get;
DomUtils
.
setAttribute
(
node
,
property
,
get
);
DomUtils
.
setAttribute
(
node
,
property
,
get
);
}
}
}
}
// Only watch for changes (double way data binding) if the binding
// Only watch for changes (double way data binding) if the binding
// has not been redefined
// has not been redefined
if
(
!
this
.
hasBinding
(
property
))
{
if
(
!
this
.
hasBinding
(
property
))
{
node
.
addEventListener
(
"
change
"
,
function
(
event
)
{
node
.
addEventListener
(
"
change
"
,
function
(
event
)
{
if
(
_model
.
has
(
modelIdx
))
{
if
(
_model
.
has
(
modelIdx
))
{
if
(
prop
)
{
if
(
prop
)
{
_model
.
update
(
modelIdx
,
name
,
node
[
property
]);
_model
.
update
(
modelIdx
,
name
,
node
[
property
]);
}
else
{
}
else
{
_model
.
set
(
modelIdx
,
node
[
property
]);
_model
.
set
(
modelIdx
,
node
[
property
]);
}
}
}
}
},
true
);
},
true
);
}
}
// Watch for changes
// Watch for changes
this
.
observers
[
modelIdx
]
=
this
.
observers
[
modelIdx
]
||
[];
this
.
observers
[
modelIdx
]
=
this
.
observers
[
modelIdx
]
||
[];
this
.
observers
[
modelIdx
].
push
(
_model
.
watchValue
(
modelIdx
,
function
(
value
)
{
this
.
observers
[
modelIdx
].
push
(
_model
.
watchValue
(
modelIdx
,
function
(
value
)
{
if
(
!
this
.
execBinding
.
apply
(
this
,
if
(
!
this
.
execBinding
.
apply
(
this
,
[
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
)]
[
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
)]
// passing extra params too
// passing extra params too
.
concat
(
extraParam
)))
{
.
concat
(
extraParam
)))
{
//node[property] = Tools.getNestedProperty(value, prop);
//node[property] = Tools.getNestedProperty(value, prop);
DomUtils
.
setAttribute
(
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
));
DomUtils
.
setAttribute
(
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
));
}
}
},
this
));
},
this
));
};
};
/**
/**
* Set the node's value into the model, the name is the model's property
* Set the node's value into the model, the name is the model's property
* @private
* @private
* @param {HTMLElement|SVGElement} node
* @param {HTMLElement|SVGElement} node
* @returns true if the property is added
* @returns true if the property is added
*/
*/
this
.
set
=
function
set
(
node
)
{
this
.
set
=
function
set
(
node
)
{
if
(
DomUtils
.
isAcceptedType
(
node
)
&&
node
.
name
)
{
if
(
DomUtils
.
isAcceptedType
(
node
)
&&
node
.
name
)
{
_model
.
set
(
node
.
name
,
node
.
value
);
_model
.
set
(
node
.
name
,
node
.
value
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
this
.
getItemIndex
=
function
getElementId
(
dom
)
{
this
.
getItemIndex
=
function
getElementId
(
dom
)
{
var
dataset
=
DomUtils
.
getDataset
(
dom
);
var
dataset
=
DomUtils
.
getDataset
(
dom
);
if
(
dataset
&&
typeof
dataset
[
this
.
plugins
.
name
+
"
_id
"
]
!=
"
undefined
"
)
{
if
(
dataset
&&
typeof
dataset
[
this
.
plugins
.
name
+
"
_id
"
]
!=
"
undefined
"
)
{
return
+
dataset
[
this
.
plugins
.
name
+
"
_id
"
];
return
+
dataset
[
this
.
plugins
.
name
+
"
_id
"
];
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Prevents the submit and set the model with all form's inputs
* Prevents the submit and set the model with all form's inputs
* @param {HTMLFormElement} for
m
* @param {HTMLFormElement} DOMfro
m
* @returns true if valid form
* @returns true if valid form
*/
*/
this
.
form
=
function
form
(
form
)
{
this
.
form
=
function
form
(
DOM
form
)
{
if
(
form
&&
form
.
nodeName
==
"
FORM
"
)
{
if
(
DOMform
&&
DOM
form
.
nodeName
==
"
FORM
"
)
{
var
that
=
this
;
var
that
=
this
;
form
.
addEventListener
(
"
submit
"
,
function
(
event
)
{
DOM
form
.
addEventListener
(
"
submit
"
,
function
(
event
)
{
Tools
.
toArray
(
form
.
querySelectorAll
(
"
[name]
"
)).
forEach
(
that
.
set
,
that
);
Tools
.
toArray
(
DOM
form
.
querySelectorAll
(
"
[name]
"
)).
forEach
(
that
.
set
,
that
);
event
.
preventDefault
();
event
.
preventDefault
();
},
true
);
},
true
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Add a new way to handle a binding
* Add a new way to handle a binding
* @param {String} name of the binding
* @param {String} name of the binding
* @param {Function} binding the function to handle the binding
* @param {Function} binding the function to handle the binding
* @returns
* @returns
*/
*/
this
.
addBinding
=
function
addBinding
(
name
,
binding
)
{
this
.
addBinding
=
function
addBinding
(
name
,
binding
)
{
if
(
name
&&
typeof
name
==
"
string
"
&&
typeof
binding
==
"
function
"
)
{
if
(
name
&&
typeof
name
==
"
string
"
&&
typeof
binding
==
"
function
"
)
{
_bindings
[
name
]
=
binding
;
_bindings
[
name
]
=
binding
;
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Execute a binding
* Execute a binding
* Only used by the plugin
* Only used by the plugin
* @private
* @private
* @param {HTMLElement} node the dom node on which to execute the binding
* @param {HTMLElement} node the dom node on which to execute the binding
* @param {String} name the name of the binding
* @param {String} name the name of the binding
* @param {Any type} value the value to pass to the function
* @param {Any type} value the value to pass to the function
* @returns
* @returns
*/
*/
this
.
execBinding
=
function
execBinding
(
node
,
name
)
{
this
.
execBinding
=
function
execBinding
(
node
,
name
)
{
if
(
this
.
hasBinding
(
name
))
{
if
(
this
.
hasBinding
(
name
))
{
_bindings
[
name
].
apply
(
node
,
Array
.
prototype
.
slice
.
call
(
arguments
,
2
));
_bindings
[
name
].
apply
(
node
,
Array
.
prototype
.
slice
.
call
(
arguments
,
2
));
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Check if the binding exists
* Check if the binding exists
* @private
* @private
* @param {String} name the name of the binding
* @param {String} name the name of the binding
* @returns
* @returns
*/
*/
this
.
hasBinding
=
function
hasBinding
(
name
)
{
this
.
hasBinding
=
function
hasBinding
(
name
)
{
return
_bindings
.
hasOwnProperty
(
name
);
return
_bindings
.
hasOwnProperty
(
name
);
};
};
/**
/**
* Get a binding
* Get a binding
* For debugging only
* For debugging only
* @private
* @private
* @param {String} name the name of the binding
* @param {String} name the name of the binding
* @returns
* @returns
*/
*/
this
.
getBinding
=
function
getBinding
(
name
)
{
this
.
getBinding
=
function
getBinding
(
name
)
{
return
_bindings
[
name
];
return
_bindings
[
name
];
};
};
/**
/**
* Add multiple binding at once
* Add multiple binding at once
* @param {Object} list the list of bindings to add
* @param {Object} list the list of bindings to add
* @returns
* @returns
*/
*/
this
.
addBindings
=
function
addBindings
(
list
)
{
this
.
addBindings
=
function
addBindings
(
list
)
{
return
Tools
.
loop
(
list
,
function
(
binding
,
name
)
{
return
Tools
.
loop
(
list
,
function
(
binding
,
name
)
{
this
.
addBinding
(
name
,
binding
);
this
.
addBinding
(
name
,
binding
);
},
this
);
},
this
);
};
};
// Inits the model
// Inits the model
this
.
setModel
(
$model
);
this
.
setModel
(
$model
);
// Inits bindings
// Inits bindings
this
.
addBindings
(
$bindings
);
this
.
addBindings
(
$bindings
);
};
};
});
});
...
@@ -754,122 +787,124 @@ define('Event.plugin',["DomUtils"],
...
@@ -754,122 +787,124 @@ define('Event.plugin',["DomUtils"],
*/
*/
function
EventPlugin
(
Utils
)
{
function
EventPlugin
(
Utils
)
{
/**
* The event plugin constructor.
* ex: new EventPlugin({method: function(){} ...}, false);
/**
* @param {Object} the object that has the event handling methods
* The event plugin constructor.
* @param {Boolean} $isMobile if the event handler has to map with touch events
* ex: new EventPlugin({method: function(){} ...}, false);
*/
* @param {Object} the object that has the event handling methods
return
function
EventPluginConstructor
(
$parent
,
$isMobile
)
{
* @param {Boolean} $isMobile if the event handler has to map with touch events
*/
/**
return
function
EventPluginConstructor
(
$parent
,
$isMobile
)
{
* The parent callback
* @private
/**
*/
* The parent callback
var
_parent
=
null
,
* @private
*/
/**
var
_parent
=
null
,
* The mapping object.
* @private
/**
*/
* The mapping object.
_map
=
{
* @private
"
mousedown
"
:
"
touchstart
"
,
*/
"
mouseup
"
:
"
touchend
"
,
_map
=
{
"
mousemove
"
:
"
touchmove
"
"
mousedown
"
:
"
touchstart
"
,
},
"
mouseup
"
:
"
touchend
"
,
"
mousemove
"
:
"
touchmove
"
/**
},
* Is touch device.
* @private
/**
*/
* Is touch device.
_isMobile
=
!!
$isMobile
;
* @private
*/
/**
_isMobile
=
!!
$isMobile
;
* Add mapped event listener (for testing purpose).
* @private
/**
*/
* Add mapped event listener (for testing purpose).
this
.
addEventListener
=
function
addEventListener
(
node
,
event
,
callback
,
useCapture
)
{
* @private
node
.
addEventListener
(
this
.
map
(
event
),
callback
,
!!
useCapture
);
*/
};
this
.
addEventListener
=
function
addEventListener
(
node
,
event
,
callback
,
useCapture
)
{
node
.
addEventListener
(
this
.
map
(
event
),
callback
,
!!
useCapture
);
/**
};
* Listen to DOM events.
* @param {Object} node DOM node
/**
* @param {String} name event's name
* Listen to DOM events.
* @param {String} listener callback's name
* @param {Object} node DOM node
* @param {String} useCapture string
* @param {String} name event's name
*/
* @param {String} listener callback's name
this
.
listen
=
function
listen
(
node
,
name
,
listener
,
useCapture
)
{
* @param {String} useCapture string
this
.
addEventListener
(
node
,
name
,
function
(
e
){
*/
_parent
[
listener
].
call
(
_parent
,
e
,
node
);
this
.
listen
=
function
listen
(
node
,
name
,
listener
,
useCapture
)
{
},
!!
useCapture
);
this
.
addEventListener
(
node
,
name
,
function
(
e
){
};
_parent
[
listener
].
call
(
_parent
,
e
,
node
);
},
!!
useCapture
);
/**
};
* Delegate the event handling to a parent DOM element
* @param {Object} node DOM node
/**
* @param {String} selector CSS3 selector to the element that listens to the event
* Delegate the event handling to a parent DOM element
* @param {String} name event's name
* @param {Object} node DOM node
* @param {String} listener callback's name
* @param {String} selector CSS3 selector to the element that listens to the event
* @param {String} useCapture string
* @param {String} name event's name
*/
* @param {String} listener callback's name
this
.
delegate
=
function
delegate
(
node
,
selector
,
name
,
listener
,
useCapture
)
{
* @param {String} useCapture string
this
.
addEventListener
(
node
,
name
,
function
(
event
){
*/
if
(
Utils
.
matches
(
node
,
selector
,
event
.
target
))
{
this
.
delegate
=
function
delegate
(
node
,
selector
,
name
,
listener
,
useCapture
)
{
_parent
[
listener
].
call
(
_parent
,
event
,
node
);
this
.
addEventListener
(
node
,
name
,
function
(
event
){
}
if
(
Utils
.
matches
(
node
,
selector
,
event
.
target
))
{
},
!!
useCapture
);
_parent
[
listener
].
call
(
_parent
,
event
,
node
);
};
}
},
!!
useCapture
);
/**
};
* Get the parent object.
* @return {Object} the parent object
/**
*/
* Get the parent object.
this
.
getParent
=
function
getParent
()
{
* @return {Object} the parent object
return
_parent
;
*/
};
this
.
getParent
=
function
getParent
()
{
return
_parent
;
/**
};
* Set the parent object.
* The parent object is an object which the functions are called by node listeners.
/**
* @param {Object} the parent object
* Set the parent object.
* @return true if object has been set
* The parent object is an object which the functions are called by node listeners.
*/
* @param {Object} the parent object
this
.
setParent
=
function
setParent
(
parent
)
{
* @return true if object has been set
if
(
parent
instanceof
Object
){
*/
_parent
=
parent
;
this
.
setParent
=
function
setParent
(
parent
)
{
return
true
;
if
(
parent
instanceof
Object
){
}
_parent
=
parent
;
return
false
;
return
true
;
};
}
return
false
;
/**
};
* Get event mapping.
* @param {String} event's name
/**
* @return the mapped event's name
* Get event mapping.
*/
* @param {String} event's name
this
.
map
=
function
map
(
name
)
{
* @return the mapped event's name
return
_isMobile
?
(
_map
[
name
]
||
name
)
:
name
;
*/
};
this
.
map
=
function
map
(
name
)
{
return
_isMobile
?
(
_map
[
name
]
||
name
)
:
name
;
/**
};
* Set event mapping.
* @param {String} event's name
/**
* @param {String} event's value
* Set event mapping.
* @return true if mapped
* @param {String} event's name
*/
* @param {String} event's value
this
.
setMap
=
function
setMap
(
name
,
value
)
{
* @return true if mapped
if
(
typeof
name
==
"
string
"
&&
*/
typeof
value
==
"
string
"
)
{
this
.
setMap
=
function
setMap
(
name
,
value
)
{
_map
[
name
]
=
value
;
if
(
typeof
name
==
"
string
"
&&
return
true
;
typeof
value
==
"
string
"
)
{
}
_map
[
name
]
=
value
;
return
false
;
return
true
;
};
}
return
false
;
//init
};
this
.
setParent
(
$parent
);
};
//init
this
.
setParent
(
$parent
);
};
});
});
...
@@ -890,6 +925,8 @@ define('LocalStore',["Store", "Tools"],
...
@@ -890,6 +925,8 @@ define('LocalStore',["Store", "Tools"],
*/
*/
function
LocalStore
(
Store
,
Tools
)
{
function
LocalStore
(
Store
,
Tools
)
{
function
LocalStoreConstructor
()
{
function
LocalStoreConstructor
()
{
/**
/**
...
@@ -971,7 +1008,7 @@ function LocalStore(Store, Tools) {
...
@@ -971,7 +1008,7 @@ function LocalStore(Store, Tools) {
return
function
LocalStoreFactory
(
init
)
{
return
function
LocalStoreFactory
(
init
)
{
LocalStoreConstructor
.
prototype
=
new
Store
(
init
);
LocalStoreConstructor
.
prototype
=
new
Store
(
init
);
return
new
LocalStoreConstructor
;
return
new
LocalStoreConstructor
()
;
};
};
});
});
...
@@ -995,6 +1032,8 @@ define('Plugins',["Tools", "DomUtils"],
...
@@ -995,6 +1032,8 @@ define('Plugins',["Tools", "DomUtils"],
*/
*/
function
Plugins
(
Tools
,
DomUtils
)
{
function
Plugins
(
Tools
,
DomUtils
)
{
return
function
PluginsConstructor
(
$plugins
)
{
return
function
PluginsConstructor
(
$plugins
)
{
/**
/**
...
@@ -1147,277 +1186,285 @@ define('OObject',["StateMachine", "Store", "Plugins", "DomUtils", "Tools"],
...
@@ -1147,277 +1186,285 @@ define('OObject',["StateMachine", "Store", "Plugins", "DomUtils", "Tools"],
*/
*/
function
OObject
(
StateMachine
,
Store
,
Plugins
,
DomUtils
,
Tools
)
{
function
OObject
(
StateMachine
,
Store
,
Plugins
,
DomUtils
,
Tools
)
{
return
function
OObjectConstructor
(
otherStore
)
{
return
function
OObjectConstructor
(
otherStore
)
{
/**
* This function creates the dom of the UI from its template
* It then queries the dom for data- attributes
* It can't be executed if the template is not set
* @private
*/
var
render
=
function
render
(
UI
)
{
// The place where the template will be created
// is either the currentPlace where the node is placed
// or a temporary div
var
baseNode
=
_currentPlace
||
document
.
createElement
(
"
div
"
);
// If the template is set
if
(
UI
.
template
)
{
// In this function, the thisObject is the UI's prototype
// UI is the UI that has OObject as prototype
if
(
typeof
UI
.
template
==
"
string
"
)
{
// Let the browser do the parsing, can't be faster & easier.
baseNode
.
innerHTML
=
UI
.
template
.
trim
();
}
else
if
(
DomUtils
.
isAcceptedType
(
UI
.
template
))
{
// If it's already an HTML element
baseNode
.
appendChild
(
UI
.
template
);
}
// The UI must be placed in a unique dom node
// If not, there can't be multiple UIs placed in the same parentNode
// as it wouldn't be possible to know which node would belong to which UI
// This is probably a DOM limitation.
if
(
baseNode
.
childNodes
.
length
>
1
)
{
throw
new
Error
(
"
UI.template should have only one parent node
"
);
}
else
{
UI
.
dom
=
baseNode
.
childNodes
[
0
];
}
UI
.
plugins
.
apply
(
UI
.
dom
);
}
else
{
// An explicit message I hope
throw
new
Error
(
"
UI.template must be set prior to render
"
);
}
},
/**
* This function appends the dom tree to the given dom node.
* This dom node should be somewhere in the dom of the application
* @private
*/
place
=
function
place
(
UI
,
DOMplace
,
beforeNode
)
{
if
(
DOMplace
)
{
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
if
(
beforeNode
)
{
DOMplace
.
insertBefore
(
UI
.
dom
,
beforeNode
);
}
else
{
DOMplace
.
appendChild
(
UI
.
dom
);
}
// Also save the new place, so next renderings
// will be made inside it
_currentPlace
=
DOMplace
;
}
},
/**
* Does rendering & placing in one function
* @private
*/
renderNPlace
=
function
renderNPlace
(
UI
,
dom
)
{
render
(
UI
);
place
.
apply
(
null
,
Tools
.
toArray
(
arguments
));
},
/**
* This stores the current place
* If this is set, this is the place where new templates
* will be appended
* @private
*/
_currentPlace
=
null
,
/**
* The UI's stateMachine.
* Much better than if(stuff) do(stuff) else if (!stuff and stuff but not stouff) do (otherstuff)
* Please open an issue if you want to propose a better one
* @private
*/
_stateMachine
=
new
StateMachine
(
"
Init
"
,
{
"
Init
"
:
[[
"
render
"
,
render
,
this
,
"
Rendered
"
],
[
"
place
"
,
renderNPlace
,
this
,
"
Rendered
"
]],
"
Rendered
"
:
[[
"
place
"
,
place
,
this
],
[
"
render
"
,
render
,
this
]]
});
/**
* The UI's Store
* It has set/get/del/has/watch/unwatch methods
* @see Emily's doc for more info on how it works.
*/
this
.
model
=
otherStore
instanceof
Store
?
otherStore
:
new
Store
();
/**
* The module that will manage the plugins for this UI
* @see Olives/Plugins' doc for more info on how it works.
*/
this
.
plugins
=
new
Plugins
();
/**
* Describes the template, can either be like "<p></p>" or HTMLElements
* @type string or HTMLElement|SVGElement
*/
this
.
template
=
null
;
/**
* This will hold the dom nodes built from the template.
*/
this
.
dom
=
null
;
/**
* Place the UI in a given dom node
* @param node the node on which to append the UI
* @param beforeNode the dom before which to append the UI
*/
this
.
place
=
function
place
(
node
,
beforeNode
)
{
_stateMachine
.
event
(
"
place
"
,
this
,
node
,
beforeNode
);
};
/**
* Renders the template to dom nodes and applies the plugins on it
* It requires the template to be set first
*/
this
.
render
=
function
render
()
{
_stateMachine
.
event
(
"
render
"
,
this
);
};
/**
* Set the UI's template from a DOM element
* @param {HTMLElement|SVGElement} dom the dom element that'll become the template of the UI
* @returns true if dom is an HTMLElement|SVGElement
*/
this
.
setTemplateFromDom
=
function
setTemplateFromDom
(
dom
)
{
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
this
.
template
=
dom
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Transforms dom nodes into a UI.
* It basically does a setTemplateFromDOM, then a place
* It's a helper function
* @param {HTMLElement|SVGElement} node the dom to transform to a UI
* @returns true if dom is an HTMLElement|SVGElement
*/
this
.
alive
=
function
alive
(
dom
)
{
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
this
.
setTemplateFromDom
(
dom
);
this
.
place
(
dom
.
parentNode
,
dom
.
nextElementSibling
);
return
true
;
}
else
{
return
false
;
}
};
/**
* Get the current dom node where the UI is placed.
* for debugging purpose
* @private
* @return {HTMLElement} node the dom where the UI is placed.
*/
this
.
getCurrentPlace
=
function
(){
return
_currentPlace
;
};
};
/**
});
* This function creates the dom of the UI from its template
* It then queries the dom for data- attributes
* It can't be executed if the template is not set
* @private
*/
var
render
=
function
render
(
UI
)
{
// The place where the template will be created
// is either the currentPlace where the node is placed
// or a temporary div
var
baseNode
=
_currentPlace
||
document
.
createElement
(
"
div
"
);
// If the template is set
if
(
UI
.
template
)
{
// In this function, the thisObject is the UI's prototype
// UI is the UI that has OObject as prototype
if
(
typeof
UI
.
template
==
"
string
"
)
{
// Let the browser do the parsing, can't be faster & easier.
baseNode
.
innerHTML
=
UI
.
template
.
trim
();
}
else
if
(
DomUtils
.
isAcceptedType
(
UI
.
template
))
{
// If it's already an HTML element
baseNode
.
appendChild
(
UI
.
template
);
}
// The UI must be placed in a unique dom node
/**
// If not, there can't be multiple UIs placed in the same parentNode
* Olives http://flams.github.com/olives
// as it wouldn't be possible to know which node would belong to which UI
* The MIT License (MIT)
// This is probably a DOM limitation.
* Copyright (c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
if
(
baseNode
.
childNodes
.
length
>
1
)
{
*/
throw
Error
(
"
UI.template should have only one parent node
"
);
}
else
{
UI
.
dom
=
baseNode
.
childNodes
[
0
];
}
UI
.
plugins
.
apply
(
UI
.
dom
);
define
(
'
Place.plugin
'
,[
"
OObject
"
,
"
Tools
"
],
/**
* @class
* Place plugin places OObject in the DOM.
* @requires OObject, Tools
*/
function
PlacePlugin
(
OObject
,
Tools
)
{
}
else
{
// An explicit message I hope
throw
Error
(
"
UI.template must be set prior to render
"
);
/**
}
* Intilialize a Place.plugin with a list of OObjects
},
* @param {Object} $uis a list of OObjects such as:
* {
* "header": new OObject(),
* "list": new OObject()
* }
* @Constructor
*/
return
function
PlacePluginConstructor
(
$uis
)
{
/**
* The list of uis currently set in this place plugin
* @private
*/
var
_uis
=
{};
/**
* Attach an OObject to this DOM element
* @param {HTML|SVGElement} node the dom node where to attach the OObject
* @param {String} the name of the OObject to attach
* @throws {NoSuchOObject} an error if there's no OObject for the given name
*/
this
.
place
=
function
place
(
node
,
name
)
{
if
(
_uis
[
name
]
instanceof
OObject
)
{
_uis
[
name
].
place
(
node
);
}
else
{
throw
new
Error
(
name
+
"
is not an OObject UI in place:
"
+
name
);
}
};
/**
* Add an OObject that can be attached to a dom element
* @param {String} the name of the OObject to add to the list
* @param {OObject} ui the OObject to add the list
* @returns {Boolean} true if the OObject was added
*/
this
.
set
=
function
set
(
name
,
ui
)
{
if
(
typeof
name
==
"
string
"
&&
ui
instanceof
OObject
)
{
_uis
[
name
]
=
ui
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Add multiple dom elements at once
* @param {Object} $uis a list of OObjects such as:
* {
* "header": new OObject(),
* "list": new OObject()
* }
*/
this
.
setAll
=
function
setAll
(
uis
)
{
Tools
.
loop
(
uis
,
function
(
ui
,
name
)
{
this
.
set
(
name
,
ui
);
},
this
);
};
/**
* Returns an OObject from the list given its name
* @param {String} the name of the OObject to get
* @returns {OObject} OObject for the given name
*/
this
.
get
=
function
get
(
name
)
{
return
_uis
[
name
];
};
this
.
setAll
(
$uis
);
};
/**
});
* This function appends the dom tree to the given dom node.
* This dom node should be somewhere in the dom of the application
* @private
*/
place
=
function
place
(
UI
,
place
,
beforeNode
)
{
if
(
place
)
{
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
beforeNode
?
place
.
insertBefore
(
UI
.
dom
,
beforeNode
)
:
place
.
appendChild
(
UI
.
dom
);
// Also save the new place, so next renderings
// will be made inside it
_currentPlace
=
place
;
}
},
/**
/**
* Does rendering & placing in one function
* Olives http://flams.github.com/olives
* @private
* The MIT License (MIT)
*/
* Copyright (c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
renderNPlace
=
function
renderNPlace
(
UI
,
dom
)
{
*/
render
(
UI
);
place
.
apply
(
null
,
Tools
.
toArray
(
arguments
));
},
/**
* This stores the current place
* If this is set, this is the place where new templates
* will be appended
* @private
*/
_currentPlace
=
null
,
/**
* The UI's stateMachine.
* Much better than if(stuff) do(stuff) else if (!stuff and stuff but not stouff) do (otherstuff)
* Please open an issue if you want to propose a better one
* @private
*/
_stateMachine
=
new
StateMachine
(
"
Init
"
,
{
"
Init
"
:
[[
"
render
"
,
render
,
this
,
"
Rendered
"
],
[
"
place
"
,
renderNPlace
,
this
,
"
Rendered
"
]],
"
Rendered
"
:
[[
"
place
"
,
place
,
this
],
[
"
render
"
,
render
,
this
]]
});
/**
* The UI's Store
* It has set/get/del/has/watch/unwatch methods
* @see Emily's doc for more info on how it works.
*/
this
.
model
=
otherStore
instanceof
Store
?
otherStore
:
new
Store
;
/**
* The module that will manage the plugins for this UI
* @see Olives/Plugins' doc for more info on how it works.
*/
this
.
plugins
=
new
Plugins
();
/**
* Describes the template, can either be like "<p></p>" or HTMLElements
* @type string or HTMLElement|SVGElement
*/
this
.
template
=
null
;
/**
* This will hold the dom nodes built from the template.
*/
this
.
dom
=
null
;
/**
* Place the UI in a given dom node
* @param node the node on which to append the UI
* @param beforeNode the dom before which to append the UI
*/
this
.
place
=
function
place
(
node
,
beforeNode
)
{
_stateMachine
.
event
(
"
place
"
,
this
,
node
,
beforeNode
);
};
/**
* Renders the template to dom nodes and applies the plugins on it
* It requires the template to be set first
*/
this
.
render
=
function
render
()
{
_stateMachine
.
event
(
"
render
"
,
this
);
};
/**
* Set the UI's template from a DOM element
* @param {HTMLElement|SVGElement} dom the dom element that'll become the template of the UI
* @returns true if dom is an HTMLElement|SVGElement
*/
this
.
setTemplateFromDom
=
function
setTemplateFromDom
(
dom
)
{
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
this
.
template
=
dom
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Transforms dom nodes into a UI.
* It basically does a setTemplateFromDOM, then a place
* It's a helper function
* @param {HTMLElement|SVGElement} node the dom to transform to a UI
* @returns true if dom is an HTMLElement|SVGElement
*/
this
.
alive
=
function
alive
(
dom
)
{
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
this
.
setTemplateFromDom
(
dom
);
this
.
place
(
dom
.
parentNode
,
dom
.
nextElementSibling
);
return
true
;
}
else
{
return
false
;
}
};
/**
* Get the current dom node where the UI is placed.
* for debugging purpose
* @private
* @return {HTMLElement} node the dom where the UI is placed.
*/
this
.
getCurrentPlace
=
function
(){
return
_currentPlace
;
};
};
});
/**
* Olives http://flams.github.com/olives
* The MIT License (MIT)
* Copyright (c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
*/
define
(
'
Place.plugin
'
,[
"
OObject
"
,
"
Tools
"
],
/**
* @class
* Place plugin places OObject in the DOM.
* @requires OObject, Tools
*/
function
PlacePlugin
(
OObject
,
Tools
)
{
/**
* Intilialize a Place.plugin with a list of OObjects
* @param {Object} $uis a list of OObjects such as:
* {
* "header": new OObject(),
* "list": new OObject()
* }
* @Constructor
*/
return
function
PlacePluginConstructor
(
$uis
)
{
/**
* The list of uis currently set in this place plugin
* @private
*/
var
_uis
=
{};
/**
* Attach an OObject to this DOM element
* @param {HTML|SVGElement} node the dom node where to attach the OObject
* @param {String} the name of the OObject to attach
* @throws {NoSuchOObject} an error if there's no OObject for the given name
*/
this
.
place
=
function
place
(
node
,
name
)
{
if
(
_uis
[
name
]
instanceof
OObject
)
{
_uis
[
name
].
place
(
node
);
}
else
{
throw
new
Error
(
name
+
"
is not an OObject UI in place:
"
+
name
);
}
};
/**
* Add an OObject that can be attached to a dom element
* @param {String} the name of the OObject to add to the list
* @param {OObject} ui the OObject to add the list
* @returns {Boolean} true if the OObject was added
*/
this
.
set
=
function
set
(
name
,
ui
)
{
if
(
typeof
name
==
"
string
"
&&
ui
instanceof
OObject
)
{
_uis
[
name
]
=
ui
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Add multiple dom elements at once
* @param {Object} $uis a list of OObjects such as:
* {
* "header": new OObject(),
* "list": new OObject()
* }
*/
this
.
setAll
=
function
setAll
(
uis
)
{
Tools
.
loop
(
uis
,
function
(
ui
,
name
)
{
this
.
set
(
name
,
ui
);
},
this
);
};
/**
* Returns an OObject from the list given its name
* @param {String} the name of the OObject to get
* @returns {OObject} OObject for the given name
*/
this
.
get
=
function
get
(
name
)
{
return
_uis
[
name
];
};
this
.
setAll
(
$uis
);
};
});
/**
* Olives http://flams.github.com/olives
* The MIT License (MIT)
* Copyright (c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
*/
define
(
'
SocketIOTransport
'
,[
"
Observable
"
,
"
Tools
"
],
define
(
'
SocketIOTransport
'
,[
"
Observable
"
,
"
Tools
"
],
/**
/**
...
@@ -1427,6 +1474,8 @@ define('SocketIOTransport',["Observable", "Tools"],
...
@@ -1427,6 +1474,8 @@ define('SocketIOTransport',["Observable", "Tools"],
*/
*/
function
SocketIOTransport
(
Observable
,
Tools
)
{
function
SocketIOTransport
(
Observable
,
Tools
)
{
/**
/**
* Defines the SocketIOTransport
* Defines the SocketIOTransport
* @private
* @private
...
@@ -1462,7 +1511,7 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -1462,7 +1511,7 @@ function SocketIOTransport(Observable, Tools) {
*/
*/
this
.
getSocket
=
function
getSocket
()
{
this
.
getSocket
=
function
getSocket
()
{
return
_socket
;
return
_socket
;
}
,
}
;
/**
/**
* Subscribe to a socket event
* Subscribe to a socket event
...
@@ -1471,7 +1520,7 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -1471,7 +1520,7 @@ function SocketIOTransport(Observable, Tools) {
*/
*/
this
.
on
=
function
on
(
event
,
func
)
{
this
.
on
=
function
on
(
event
,
func
)
{
return
_socket
.
on
(
event
,
func
);
return
_socket
.
on
(
event
,
func
);
}
,
}
;
/**
/**
* Subscribe to a socket event but disconnect as soon as it fires.
* Subscribe to a socket event but disconnect as soon as it fires.
...
@@ -1510,15 +1559,17 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -1510,15 +1559,17 @@ function SocketIOTransport(Observable, Tools) {
* @param {Object} scope the scope in which to execute the callback
* @param {Object} scope the scope in which to execute the callback
*/
*/
this
.
request
=
function
request
(
channel
,
data
,
func
,
scope
)
{
this
.
request
=
function
request
(
channel
,
data
,
func
,
scope
)
{
if
(
typeof
channel
==
"
string
"
if
(
typeof
channel
==
"
string
"
&&
&&
typeof
data
!=
"
undefined
"
)
{
typeof
data
!=
"
undefined
"
)
{
var
reqData
=
{
var
reqData
=
{
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
data
:
data
data
:
data
},
},
boundCallback
=
function
()
{
boundCallback
=
function
()
{
func
&&
func
.
apply
(
scope
||
null
,
arguments
);
if
(
func
)
{
func
.
apply
(
scope
||
null
,
arguments
);
}
};
};
this
.
once
(
reqData
.
eventId
,
boundCallback
);
this
.
once
(
reqData
.
eventId
,
boundCallback
);
...
@@ -1540,9 +1591,9 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -1540,9 +1591,9 @@ function SocketIOTransport(Observable, Tools) {
* @returns
* @returns
*/
*/
this
.
listen
=
function
listen
(
channel
,
data
,
func
,
scope
)
{
this
.
listen
=
function
listen
(
channel
,
data
,
func
,
scope
)
{
if
(
typeof
channel
==
"
string
"
if
(
typeof
channel
==
"
string
"
&&
&&
typeof
data
!=
"
undefined
"
typeof
data
!=
"
undefined
"
&&
&&
typeof
func
==
"
function
"
)
{
typeof
func
==
"
function
"
)
{
var
reqData
=
{
var
reqData
=
{
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
...
@@ -1550,7 +1601,9 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -1550,7 +1601,9 @@ function SocketIOTransport(Observable, Tools) {
keepAlive
:
true
keepAlive
:
true
},
},
boundCallback
=
function
()
{
boundCallback
=
function
()
{
func
&&
func
.
apply
(
scope
||
null
,
arguments
);
if
(
func
)
{
func
.
apply
(
scope
||
null
,
arguments
);
}
},
},
that
=
this
;
that
=
this
;
...
@@ -1573,3 +1626,504 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -1573,3 +1626,504 @@ function SocketIOTransport(Observable, Tools) {
this
.
setSocket
(
$socket
);
this
.
setSocket
(
$socket
);
};
};
});
});
/**
* Olives http://flams.github.com/olives
* The MIT License (MIT)
* Copyright (c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
*/
define
(
'
Stack
'
,[
'
Tools
'
],
/**
* @class
* A Stack is a tool for managing DOM elements as groups. Within a group, dom elements
* can be added, removed, moved around. The group can be moved to another parent node
* while keeping the DOM elements in the same order, excluding the parent dom elements's
* children that are not in the Stack.
*/
function
Stack
()
{
var
Tools
=
require
(
"
Tools
"
);
return
function
StackConstructor
(
$parent
)
{
/**
* The parent DOM element is a documentFragment by default
* @private
*/
var
_parent
=
document
.
createDocumentFragment
(),
/**
* The place where the dom elements hide
* @private
*/
_hidePlace
=
document
.
createElement
(
"
div
"
),
/**
* The list of dom elements that are part of the stack
* Helps for excluding elements that are not part of it
* @private
*/
_childNodes
=
[],
_lastTransit
=
null
;
/**
* Add a DOM element to the stack. It will be appended.
* @param {HTMLElement} dom the DOM element to add
* @returns {HTMLElement} dom
*/
this
.
add
=
function
add
(
dom
)
{
if
(
!
this
.
has
(
dom
)
&&
dom
instanceof
HTMLElement
)
{
_parent
.
appendChild
(
dom
);
_childNodes
.
push
(
dom
);
return
dom
;
}
else
{
return
false
;
}
};
/**
* Remove a DOM element from the stack.
* @param {HTMLElement} dom the DOM element to remove
* @returns {HTMLElement} dom
*/
this
.
remove
=
function
remove
(
dom
)
{
var
index
;
if
(
this
.
has
(
dom
))
{
index
=
_childNodes
.
indexOf
(
dom
);
_parent
.
removeChild
(
dom
);
_childNodes
.
splice
(
index
,
1
);
return
dom
;
}
else
{
return
false
;
}
};
/**
* Place a stack by appending its DOM elements to a new parent
* @param {HTMLElement} newParentDom the new DOM element to append the stack to
* @returns {HTMLElement} newParentDom
*/
this
.
place
=
function
place
(
newParentDom
)
{
if
(
newParentDom
instanceof
HTMLElement
)
{
[].
slice
.
call
(
_parent
.
childNodes
).
forEach
(
function
(
childDom
)
{
if
(
this
.
has
(
childDom
))
{
newParentDom
.
appendChild
(
childDom
);
}
},
this
);
return
this
.
_setParent
(
newParentDom
);
}
else
{
return
false
;
}
};
/**
* Move an element up in the stack
* @param {HTMLElement} dom the dom element to move up
* @returns {HTMLElement} dom
*/
this
.
up
=
function
up
(
dom
)
{
if
(
this
.
has
(
dom
))
{
var
domPosition
=
this
.
getPosition
(
dom
);
this
.
move
(
dom
,
domPosition
+
1
);
return
dom
;
}
else
{
return
false
;
}
};
/**
* Move an element down in the stack
* @param {HTMLElement} dom the dom element to move down
* @returns {HTMLElement} dom
*/
this
.
down
=
function
down
(
dom
)
{
if
(
this
.
has
(
dom
))
{
var
domPosition
=
this
.
getPosition
(
dom
);
this
.
move
(
dom
,
domPosition
-
1
);
return
dom
;
}
else
{
return
false
;
}
};
/**
* Move an element that is already in the stack to a new position
* @param {HTMLElement} dom the dom element to move
* @param {Number} position the position to which to move the DOM element
* @returns {HTMLElement} dom
*/
this
.
move
=
function
move
(
dom
,
position
)
{
if
(
this
.
has
(
dom
))
{
var
domIndex
=
_childNodes
.
indexOf
(
dom
);
_childNodes
.
splice
(
domIndex
,
1
);
// Preventing a bug in IE when insertBefore is not given a valid
// second argument
var
nextElement
=
getNextElementInDom
(
position
);
if
(
nextElement
)
{
_parent
.
insertBefore
(
dom
,
nextElement
);
}
else
{
_parent
.
appendChild
(
dom
);
}
_childNodes
.
splice
(
position
,
0
,
dom
);
return
dom
;
}
else
{
return
false
;
}
};
function
getNextElementInDom
(
position
)
{
if
(
position
>=
_childNodes
.
length
)
{
return
;
}
var
nextElement
=
_childNodes
[
position
];
if
(
Tools
.
toArray
(
_parent
.
childNodes
).
indexOf
(
nextElement
)
==
-
1
)
{
return
getNextElementInDom
(
position
+
1
);
}
else
{
return
nextElement
;
}
}
/**
* Insert a new element at a specific position in the stack
* @param {HTMLElement} dom the dom element to insert
* @param {Number} position the position to which to insert the DOM element
* @returns {HTMLElement} dom
*/
this
.
insert
=
function
insert
(
dom
,
position
)
{
if
(
!
this
.
has
(
dom
)
&&
dom
instanceof
HTMLElement
)
{
_childNodes
.
splice
(
position
,
0
,
dom
);
_parent
.
insertBefore
(
dom
,
_parent
.
childNodes
[
position
]);
return
dom
;
}
else
{
return
false
;
}
};
/**
* Get the position of an element in the stack
* @param {HTMLElement} dom the dom to get the position from
* @returns {HTMLElement} dom
*/
this
.
getPosition
=
function
getPosition
(
dom
)
{
return
_childNodes
.
indexOf
(
dom
);
};
/**
* Count the number of elements in a stack
* @returns {Number} the number of items
*/
this
.
count
=
function
count
()
{
return
_parent
.
childNodes
.
length
;
};
/**
* Tells if a DOM element is in the stack
* @param {HTMLElement} dom the dom to tell if its in the stack
* @returns {HTMLElement} dom
*/
this
.
has
=
function
has
(
childDom
)
{
return
this
.
getPosition
(
childDom
)
>=
0
;
};
/**
* Hide a dom element that was previously added to the stack
* It will be taken out of the dom until displayed again
* @param {HTMLElement} dom the dom to hide
* @return {boolean} if dom element is in the stack
*/
this
.
hide
=
function
hide
(
dom
)
{
if
(
this
.
has
(
dom
))
{
_hidePlace
.
appendChild
(
dom
);
return
true
;
}
else
{
return
false
;
}
};
/**
* Show a dom element that was previously hidden
* It will be added back to the dom
* @param {HTMLElement} dom the dom to show
* @return {boolean} if dom element is current hidden
*/
this
.
show
=
function
show
(
dom
)
{
if
(
this
.
has
(
dom
)
&&
dom
.
parentNode
===
_hidePlace
)
{
this
.
move
(
dom
,
_childNodes
.
indexOf
(
dom
));
return
true
;
}
else
{
return
false
;
}
};
/**
* Helper function for hiding all the dom elements
*/
this
.
hideAll
=
function
hideAll
()
{
_childNodes
.
forEach
(
this
.
hide
,
this
);
};
/**
* Helper function for showing all the dom elements
*/
this
.
showAll
=
function
showAll
()
{
_childNodes
.
forEach
(
this
.
show
,
this
);
};
/**
* Get the parent node that a stack is currently attached to
* @returns {HTMLElement} parent node
*/
this
.
getParent
=
function
_getParent
()
{
return
_parent
;
};
/**
* Set the parent element (without appending the stacks dom elements to)
* @private
*/
this
.
_setParent
=
function
_setParent
(
parent
)
{
if
(
parent
instanceof
HTMLElement
)
{
_parent
=
parent
;
return
_parent
;
}
else
{
return
false
;
}
};
/**
* Get the place where the DOM elements are hidden
* @private
*/
this
.
getHidePlace
=
function
getHidePlace
()
{
return
_hidePlace
;
};
/**
* Set the place where the DOM elements are hidden
* @private
*/
this
.
setHidePlace
=
function
setHidePlace
(
hidePlace
)
{
if
(
hidePlace
instanceof
HTMLElement
)
{
_hidePlace
=
hidePlace
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Get the last dom element that the stack transitted to
* @returns {HTMLElement} the last dom element
*/
this
.
getLastTransit
=
function
getLastTransit
()
{
return
_lastTransit
;
};
/**
* Transit between views, will show the new one and hide the previous
* element that the stack transitted to, if any.
* @param {HTMLElement} dom the element to transit to
* @returns {Boolean} false if the element can't be shown
*/
this
.
transit
=
function
transit
(
dom
)
{
if
(
_lastTransit
)
{
this
.
hide
(
_lastTransit
);
}
if
(
this
.
show
(
dom
))
{
_lastTransit
=
dom
;
return
true
;
}
else
{
return
false
;
}
};
this
.
_setParent
(
$parent
);
};
});
/**
* Olives http://flams.github.com/olives
* The MIT License (MIT)
* Copyright (c) 2012-2013 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
*/
define
(
'
LocationRouter
'
,[
"
Router
"
,
"
Tools
"
],
/**
* @class
* A locationRouter is a router which navigates to the route defined in the URL and updates this URL
* while navigating. It's a subtype of Emily's Router
*/
function
LocationRouter
(
Router
,
Tools
)
{
function
LocationRouterConstructor
()
{
/**
* The handle on the watch
* @private
*/
var
_watchHandle
,
/**
* The default route to navigate to when nothing is supplied in the url
* @private
*/
_defaultRoute
=
""
,
/**
* The last route that was navigated to
* @private
*/
_lastRoute
=
window
.
location
.
hash
;
/**
* Navigates to the current hash or to the default route if none is supplied in the url
* @private
*/
/*jshint validthis:true*/
function
doNavigate
()
{
if
(
window
.
location
.
hash
)
{
var
parsedHash
=
this
.
parse
(
window
.
location
.
hash
);
this
.
navigate
.
apply
(
this
,
parsedHash
);
}
else
{
this
.
navigate
(
_defaultRoute
);
}
}
/**
* Set the default route to navigate to when nothing is defined in the url
* @param {String} defaultRoute the defaultRoute to navigate to
* @returns {Boolean} true if it's not an empty string
*/
this
.
setDefaultRoute
=
function
setDefaultRoute
(
defaultRoute
)
{
if
(
defaultRoute
&&
typeof
defaultRoute
==
"
string
"
)
{
_defaultRoute
=
defaultRoute
;
return
true
;
}
else
{
return
false
;
}
};
/**
* Get the currently set default route
* @returns {String} the default route
*/
this
.
getDefaultRoute
=
function
getDefaultRoute
()
{
return
_defaultRoute
;
};
/**
* The function that parses the url to determine the route to navigate to.
* It has a default behavior explained below, but can be overriden as long as
* it has the same contract.
* @param {String} hash the hash coming from window.location.has
* @returns {Array} has to return an array with the list of arguments to call
* navigate with. The first item of the array must be the name of the route.
*
* Example: #album/holiday/2013
* will navigate to the route "album" and give two arguments "holiday" and "2013"
*/
this
.
parse
=
function
parse
(
hash
)
{
return
hash
.
split
(
"
#
"
).
pop
().
split
(
"
/
"
);
};
/**
* The function that converts, or serialises the route and its arguments to a valid URL.
* It has a default behavior below, but can be overriden as long as it has the same contract.
* @param {Array} args the list of arguments to serialize
* @returns {String} the serialized arguments to add to the url hashmark
*
* Example:
* ["album", "holiday", "2013"];
* will give "album/holiday/2013"
*
*/
this
.
toUrl
=
function
toUrl
(
args
)
{
return
args
.
join
(
"
/
"
);
};
/**
* When all the routes and handlers have been defined, start the location router
* so it parses the URL and navigates to the corresponding route.
* It will also start listening to route changes and hashmark changes to navigate.
* While navigating, the hashmark itself will also change to reflect the current route state
*/
this
.
start
=
function
start
(
defaultRoute
)
{
this
.
setDefaultRoute
(
defaultRoute
);
doNavigate
.
call
(
this
);
this
.
bindOnHashChange
();
this
.
bindOnRouteChange
();
};
/**
* Remove the events handler for cleaning.
*/
this
.
destroy
=
function
destroy
()
{
this
.
unwatch
(
_watchHandle
);
window
.
removeEventListener
(
"
hashchange
"
,
this
.
boundOnHashChange
,
true
);
};
/**
* Parse the hash and navigate to the corresponding url
* @private
*/
this
.
onHashChange
=
function
onHashChange
()
{
if
(
window
.
location
.
hash
!=
_lastRoute
)
{
doNavigate
.
call
(
this
);
}
};
/**
* The bound version of onHashChange for add/removeEventListener
* @private
*/
this
.
boundOnHashChange
=
this
.
onHashChange
.
bind
(
this
);
/**
* Add an event listener to hashchange to navigate to the corresponding route
* when it changes
* @private
*/
this
.
bindOnHashChange
=
function
bindOnHashChange
()
{
window
.
addEventListener
(
"
hashchange
"
,
this
.
boundOnHashChange
,
true
);
};
/**
* Watch route change events from the router to update the location
* @private
*/
this
.
bindOnRouteChange
=
function
bindOnRouteChange
()
{
_watchHandle
=
this
.
watch
(
this
.
onRouteChange
,
this
);
};
/**
* The handler for when the route changes
* It updates the location
* @private
*/
this
.
onRouteChange
=
function
onRouteChange
()
{
window
.
location
.
hash
=
this
.
toUrl
(
Tools
.
toArray
(
arguments
));
_lastRoute
=
window
.
location
.
hash
;
};
this
.
getLastRoute
=
function
getLastRoute
()
{
return
_lastRoute
;
};
}
return
function
LocationRouterFactory
()
{
LocationRouterConstructor
.
prototype
=
new
Router
();
return
new
LocationRouterConstructor
();
};
});
examples/olives/bower_components/olives/src/Bind.plugin.js
View file @
9df98e41
...
@@ -13,375 +13,406 @@ define(["Store", "Observable", "Tools", "DomUtils"],
...
@@ -13,375 +13,406 @@ define(["Store", "Observable", "Tools", "DomUtils"],
*/
*/
function
BindPlugin
(
Store
,
Observable
,
Tools
,
DomUtils
)
{
function
BindPlugin
(
Store
,
Observable
,
Tools
,
DomUtils
)
{
return
function
BindPluginConstructor
(
$model
,
$bindings
)
{
"
use strict
"
;
/**
return
function
BindPluginConstructor
(
$model
,
$bindings
)
{
* The model to watch
* @private
/**
*/
* The model to watch
var
_model
=
null
,
* @private
*/
/**
var
_model
=
null
,
* The list of custom bindings
* @private
/**
*/
* The list of custom bindings
_bindings
=
{},
* @private
*/
/**
_bindings
=
{},
* The list of itemRenderers
* each foreach has its itemRenderer
/**
* @private
* The list of itemRenderers
*/
* each foreach has its itemRenderer
_itemRenderers
=
{};
* @private
*/
/**
_itemRenderers
=
{},
* The observers handlers
* for debugging only
/**
* @private
* The observers handlers
*/
* @private
this
.
observers
=
{};
*/
_observers
=
{};
/**
* Define the model to watch for
/**
* @param {Store} model the model to watch for changes
* Exposed for debugging purpose
* @returns {Boolean} true if the model was set
* @private
*/
*/
this
.
setModel
=
function
setModel
(
model
)
{
this
.
observers
=
_observers
;
if
(
model
instanceof
Store
)
{
// Set the model
function
_removeObserversForId
(
id
)
{
_model
=
model
;
if
(
_observers
[
id
])
{
return
true
;
_observers
[
id
].
forEach
(
function
(
handler
)
{
}
else
{
_model
.
unwatchValue
(
handler
);
return
false
;
});
}
delete
_observers
[
id
];
};
}
}
/**
* Get the store that is watched for
/**
* for debugging only
* Define the model to watch for
* @private
* @param {Store} model the model to watch for changes
* @returns the Store
* @returns {Boolean} true if the model was set
*/
*/
this
.
getModel
=
function
getModel
()
{
this
.
setModel
=
function
setModel
(
model
)
{
return
_model
;
if
(
model
instanceof
Store
)
{
};
// Set the model
_model
=
model
;
/**
return
true
;
* The item renderer defines a dom node that can be duplicated
}
else
{
* It is made available for debugging purpose, don't use it
return
false
;
* @private
}
*/
};
this
.
ItemRenderer
=
function
ItemRenderer
(
$plugins
,
$rootNode
)
{
/**
/**
* Get the store that is watched for
* The node that will be cloned
* for debugging only
* @private
* @private
*/
* @returns the Store
var
_node
=
null
,
*/
this
.
getModel
=
function
getModel
()
{
/**
return
_model
;
* The object that contains plugins.name and plugins.apply
};
* @private
*/
/**
_plugins
=
null
,
* The item renderer defines a dom node that can be duplicated
* It is made available for debugging purpose, don't use it
/**
* @private
* The _rootNode where to append the created items
*/
* @private
this
.
ItemRenderer
=
function
ItemRenderer
(
$plugins
,
$rootNode
)
{
*/
_rootNode
=
null
,
/**
* The node that will be cloned
/**
* @private
* The lower boundary
*/
* @private
var
_node
=
null
,
*/
_start
=
null
,
/**
* The object that contains plugins.name and plugins.apply
/**
* @private
* The number of item to display
*/
* @private
_plugins
=
null
,
*/
_nb
=
null
;
/**
* The _rootNode where to append the created items
/**
* @private
* Set the duplicated node
*/
* @private
_rootNode
=
null
,
*/
this
.
setRenderer
=
function
setRenderer
(
node
)
{
/**
_node
=
node
;
* The lower boundary
return
true
;
* @private
};
*/
_start
=
null
,
/**
* Returns the node that is going to be used for rendering
/**
* @private
* The number of item to display
* @returns the node that is duplicated
* @private
*/
*/
this
.
getRenderer
=
function
getRenderer
()
{
_nb
=
null
;
return
_node
;
};
/**
* Set the duplicated node
/**
* @private
* Sets the rootNode and gets the node to copy
*/
* @private
this
.
setRenderer
=
function
setRenderer
(
node
)
{
* @param {HTMLElement|SVGElement} rootNode
_node
=
node
;
* @returns
return
true
;
*/
};
this
.
setRootNode
=
function
setRootNode
(
rootNode
)
{
var
renderer
;
/**
if
(
DomUtils
.
isAcceptedType
(
rootNode
))
{
* Returns the node that is going to be used for rendering
_rootNode
=
rootNode
;
* @private
renderer
=
_rootNode
.
querySelector
(
"
*
"
);
* @returns the node that is duplicated
this
.
setRenderer
(
renderer
);
*/
renderer
&&
_rootNode
.
removeChild
(
renderer
);
this
.
getRenderer
=
function
getRenderer
()
{
return
true
;
return
_node
;
}
else
{
};
return
false
;
}
/**
};
* Sets the rootNode and gets the node to copy
* @private
/**
* @param {HTMLElement|SVGElement} rootNode
* Gets the rootNode
* @returns
* @private
*/
* @returns _rootNode
this
.
setRootNode
=
function
setRootNode
(
rootNode
)
{
*/
var
renderer
;
this
.
getRootNode
=
function
getRootNode
()
{
if
(
DomUtils
.
isAcceptedType
(
rootNode
))
{
return
_rootNode
;
_rootNode
=
rootNode
;
};
renderer
=
_rootNode
.
querySelector
(
"
*
"
);
this
.
setRenderer
(
renderer
);
/**
if
(
renderer
)
{
* Set the plugins objet that contains the name and the apply function
_rootNode
.
removeChild
(
renderer
);
* @private
}
* @param plugins
return
true
;
* @returns true
}
else
{
*/
return
false
;
this
.
setPlugins
=
function
setPlugins
(
plugins
)
{
}
_plugins
=
plugins
;
};
return
true
;
};
/**
* Gets the rootNode
/**
* @private
* Get the plugins object
* @returns _rootNode
* @private
*/
* @returns the plugins object
this
.
getRootNode
=
function
getRootNode
()
{
*/
return
_rootNode
;
this
.
getPlugins
=
function
getPlugins
()
{
};
return
_plugins
;
};
/**
* Set the plugins objet that contains the name and the apply function
/**
* @private
* The nodes created from the items are stored here
* @param plugins
* @private
* @returns true
*/
*/
this
.
items
=
new
Store
([]);
this
.
setPlugins
=
function
setPlugins
(
plugins
)
{
_plugins
=
plugins
;
/**
return
true
;
* Set the start limit
};
* @private
* @param {Number} start the value to start rendering the items from
/**
* @returns the value
* Get the plugins object
*/
* @private
this
.
setStart
=
function
setStart
(
start
)
{
* @returns the plugins object
return
_start
=
parseInt
(
start
,
10
);
*/
};
this
.
getPlugins
=
function
getPlugins
()
{
return
_plugins
;
/**
};
* Get the start value
* @private
/**
* @returns the start value
* The nodes created from the items are stored here
*/
* @private
this
.
getStart
=
function
getStart
()
{
*/
return
_start
;
this
.
items
=
{};
};
/**
/**
* Set the start limit
* Set the number of item to display
* @private
* @private
* @param {Number} start the value to start rendering the items from
* @param {Number/String} nb the number of item to display or "*" for all
* @returns the value
* @returns the value
*/
*/
this
.
setStart
=
function
setStart
(
start
)
{
this
.
setNb
=
function
setNb
(
nb
)
{
_start
=
parseInt
(
start
,
10
);
return
_nb
=
nb
==
"
*
"
?
nb
:
parseInt
(
nb
,
10
);
return
_start
;
};
};
/**
/**
* Get the number of item to display
* Get the start value
* @private
* @private
* @returns the value
* @returns the start value
*/
*/
this
.
getNb
=
function
getNb
()
{
this
.
getStart
=
function
getStart
()
{
return
_nb
;
return
_start
;
};
};
/**
/**
* Adds a new item and adds it in the items list
* Set the number of item to display
* @private
* @private
* @param {Number} id the id of the item
* @param {Number/String} nb the number of item to display or "*" for all
* @returns
* @returns the value
*/
*/
this
.
addItem
=
function
addItem
(
id
)
{
this
.
setNb
=
function
setNb
(
nb
)
{
var
node
,
_nb
=
nb
==
"
*
"
?
nb
:
parseInt
(
nb
,
10
);
next
;
return
_nb
;
};
if
(
typeof
id
==
"
number
"
&&
!
this
.
items
.
get
(
id
))
{
node
=
this
.
create
(
id
);
/**
if
(
node
)
{
* Get the number of item to display
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
* @private
next
=
this
.
getNextItem
(
id
);
* @returns the value
next
?
_rootNode
.
insertBefore
(
node
,
next
)
:
_rootNode
.
appendChild
(
node
);
*/
return
true
;
this
.
getNb
=
function
getNb
()
{
}
else
{
return
_nb
;
return
false
;
};
}
}
else
{
/**
return
false
;
* Adds a new item and adds it in the items list
}
* @private
};
* @param {Number} id the id of the item
* @returns
/**
*/
* Get the next item in the item store given an id.
this
.
addItem
=
function
addItem
(
id
)
{
* @private
var
node
,
* @param {Number} id the id to start from
next
;
* @returns
*/
if
(
typeof
id
==
"
number
"
&&
!
this
.
items
[
id
])
{
this
.
getNextItem
=
function
getNextItem
(
id
)
{
next
=
this
.
getNextItem
(
id
);
return
this
.
items
.
alter
(
"
slice
"
,
id
+
1
).
filter
(
function
(
value
)
{
node
=
this
.
create
(
id
);
if
(
DomUtils
.
isAcceptedType
(
value
))
{
if
(
node
)
{
return
true
;
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
}
if
(
next
)
{
})[
0
];
_rootNode
.
insertBefore
(
node
,
next
);
};
}
else
{
_rootNode
.
appendChild
(
node
);
/**
}
* Remove an item from the dom and the items list
return
true
;
* @private
}
else
{
* @param {Number} id the id of the item to remove
return
false
;
* @returns
}
*/
}
else
{
this
.
removeItem
=
function
removeItem
(
id
)
{
return
false
;
var
item
=
this
.
items
.
get
(
id
);
}
if
(
item
)
{
};
_rootNode
.
removeChild
(
item
);
this
.
items
.
set
(
id
);
/**
return
true
;
* Get the next item in the item store given an id.
}
else
{
* @private
return
false
;
* @param {Number} id the id to start from
}
* @returns
};
*/
this
.
getNextItem
=
function
getNextItem
(
id
)
{
/**
var
keys
=
Object
.
keys
(
this
.
items
).
map
(
function
(
string
)
{
* create a new node. Actually makes a clone of the initial one
return
Number
(
string
);
* and adds pluginname_id to each node, then calls plugins.apply to apply all plugins
}),
* @private
closest
=
Tools
.
closestGreater
(
id
,
keys
),
* @param id
closestId
=
keys
[
closest
];
* @param pluginName
* @returns the associated node
// Only return if different
*/
if
(
closestId
!=
id
)
{
this
.
create
=
function
create
(
id
)
{
return
this
.
items
[
closestId
];
if
(
_model
.
has
(
id
))
{
}
else
{
var
newNode
=
_node
.
cloneNode
(
true
),
return
;
nodes
=
DomUtils
.
getNodes
(
newNode
);
}
};
Tools
.
toArray
(
nodes
).
forEach
(
function
(
child
)
{
child
.
setAttribute
(
"
data-
"
+
_plugins
.
name
+
"
_id
"
,
id
);
/**
});
* Remove an item from the dom and the items list
* @private
this
.
items
.
set
(
id
,
newNode
);
* @param {Number} id the id of the item to remove
_plugins
.
apply
(
newNode
);
* @returns
return
newNode
;
*/
}
this
.
removeItem
=
function
removeItem
(
id
)
{
};
var
item
=
this
.
items
[
id
];
if
(
item
)
{
/**
_rootNode
.
removeChild
(
item
);
* Renders the dom tree, adds nodes that are in the boundaries
delete
this
.
items
[
id
];
* and removes the others
_removeObserversForId
(
id
);
* @private
return
true
;
* @returns true boundaries are set
}
else
{
*/
return
false
;
this
.
render
=
function
render
()
{
}
// If the number of items to render is all (*)
};
// Then get the number of items
var
_tmpNb
=
_nb
==
"
*
"
?
_model
.
getNbItems
()
:
_nb
;
/**
* create a new node. Actually makes a clone of the initial one
// This will store the items to remove
* and adds pluginname_id to each node, then calls plugins.apply to apply all plugins
var
marked
=
[];
* @private
* @param id
// Render only if boundaries have been set
* @param pluginName
if
(
_nb
!==
null
&&
_start
!==
null
)
{
* @returns the associated node
*/
// Loop through the existing items
this
.
create
=
function
create
(
id
)
{
this
.
items
.
loop
(
function
(
value
,
idx
)
{
if
(
_model
.
has
(
id
))
{
// If an item is out of the boundary
var
newNode
=
_node
.
cloneNode
(
true
),
if
(
idx
<
_start
||
idx
>=
(
_start
+
_tmpNb
)
||
!
_model
.
has
(
idx
))
{
nodes
=
DomUtils
.
getNodes
(
newNode
);
// Mark it
marked
.
push
(
idx
);
Tools
.
toArray
(
nodes
).
forEach
(
function
(
child
)
{
}
child
.
setAttribute
(
"
data-
"
+
_plugins
.
name
+
"
_id
"
,
id
);
},
this
);
});
// Remove the marked item from the highest id to the lowest
this
.
items
[
id
]
=
newNode
;
// Doing this will avoid the id change during removal
_plugins
.
apply
(
newNode
);
// (removing id 2 will make id 3 becoming 2)
return
newNode
;
marked
.
sort
(
Tools
.
compareNumbers
).
reverse
().
forEach
(
this
.
removeItem
,
this
);
}
};
// Now that we have removed the old nodes
// Add the missing one
/**
for
(
var
i
=
_start
,
l
=
_tmpNb
+
_start
;
i
<
l
;
i
++
)
{
* Renders the dom tree, adds nodes that are in the boundaries
this
.
addItem
(
i
);
* and removes the others
}
* @private
return
true
;
* @returns true boundaries are set
}
else
{
*/
return
false
;
this
.
render
=
function
render
()
{
}
// If the number of items to render is all (*)
};
// Then get the number of items
var
_tmpNb
=
_nb
==
"
*
"
?
_model
.
getNbItems
()
:
_nb
;
this
.
setPlugins
(
$plugins
);
this
.
setRootNode
(
$rootNode
);
// This will store the items to remove
};
var
marked
=
[];
/**
// Render only if boundaries have been set
* Save an itemRenderer according to its id
if
(
_nb
!==
null
&&
_start
!==
null
)
{
* @private
* @param {String} id the id of the itemRenderer
// Loop through the existing items
* @param {ItemRenderer} itemRenderer an itemRenderer object
Tools
.
loop
(
this
.
items
,
function
(
value
,
idx
)
{
*/
// If an item is out of the boundary
this
.
setItemRenderer
=
function
setItemRenderer
(
id
,
itemRenderer
)
{
idx
=
Number
(
idx
);
id
=
id
||
"
default
"
;
_itemRenderers
[
id
]
=
itemRenderer
;
if
(
idx
<
_start
||
idx
>=
(
_start
+
_tmpNb
)
||
!
_model
.
has
(
idx
))
{
};
// Mark it
marked
.
push
(
idx
);
/**
}
* Get an itemRenderer
},
this
);
* @private
* @param {String} id the name of the itemRenderer
// Remove the marked item from the highest id to the lowest
* @returns the itemRenderer
// Doing this will avoid the id change during removal
*/
// (removing id 2 will make id 3 becoming 2)
this
.
getItemRenderer
=
function
getItemRenderer
(
id
)
{
marked
.
sort
(
Tools
.
compareNumbers
).
reverse
().
forEach
(
this
.
removeItem
,
this
);
return
_itemRenderers
[
id
];
};
// Now that we have removed the old nodes
// Add the missing one
/**
for
(
var
i
=
_start
,
l
=
_tmpNb
+
_start
;
i
<
l
;
i
++
)
{
* Expands the inner dom nodes of a given dom node, filling it with model's values
this
.
addItem
(
i
);
* @param {HTMLElement|SVGElement} node the dom node to apply foreach to
}
*/
return
true
;
this
.
foreach
=
function
foreach
(
node
,
idItemRenderer
,
start
,
nb
)
{
}
else
{
var
itemRenderer
=
new
this
.
ItemRenderer
(
this
.
plugins
,
node
);
return
false
;
}
itemRenderer
.
setStart
(
start
||
0
);
};
itemRenderer
.
setNb
(
nb
||
"
*
"
);
this
.
setPlugins
(
$plugins
);
itemRenderer
.
render
();
this
.
setRootNode
(
$rootNode
);
};
// Add the newly created item
/**
* Save an itemRenderer according to its id
* @private
* @param {String} id the id of the itemRenderer
* @param {ItemRenderer} itemRenderer an itemRenderer object
*/
this
.
setItemRenderer
=
function
setItemRenderer
(
id
,
itemRenderer
)
{
id
=
id
||
"
default
"
;
_itemRenderers
[
id
]
=
itemRenderer
;
};
/**
* Get an itemRenderer
* @private
* @param {String} id the name of the itemRenderer
* @returns the itemRenderer
*/
this
.
getItemRenderer
=
function
getItemRenderer
(
id
)
{
return
_itemRenderers
[
id
];
};
/**
* Expands the inner dom nodes of a given dom node, filling it with model's values
* @param {HTMLElement|SVGElement} node the dom node to apply foreach to
*/
this
.
foreach
=
function
foreach
(
node
,
idItemRenderer
,
start
,
nb
)
{
var
itemRenderer
=
new
this
.
ItemRenderer
(
this
.
plugins
,
node
);
itemRenderer
.
setStart
(
start
||
0
);
itemRenderer
.
setNb
(
nb
||
"
*
"
);
itemRenderer
.
render
();
// Add the newly created item
_model
.
watch
(
"
added
"
,
itemRenderer
.
render
,
itemRenderer
);
_model
.
watch
(
"
added
"
,
itemRenderer
.
render
,
itemRenderer
);
// If an item is deleted
// If an item is deleted
_model
.
watch
(
"
deleted
"
,
function
(
idx
)
{
_model
.
watch
(
"
deleted
"
,
function
(
idx
)
{
itemRenderer
.
render
();
itemRenderer
.
render
();
// Also remove all observers
// Also remove all observers
this
.
observers
[
idx
]
&&
this
.
observers
[
idx
].
forEach
(
function
(
handler
)
{
_removeObserversForId
(
idx
);
_model
.
unwatchValue
(
handler
);
},
this
);
delete
this
.
observers
[
idx
];
},
this
);
},
this
);
this
.
setItemRenderer
(
idItemRenderer
,
itemRenderer
);
this
.
setItemRenderer
(
idItemRenderer
,
itemRenderer
);
...
@@ -394,13 +425,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
...
@@ -394,13 +425,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
* @returns true if the foreach exists
* @returns true if the foreach exists
*/
*/
this
.
updateStart
=
function
updateStart
(
id
,
start
)
{
this
.
updateStart
=
function
updateStart
(
id
,
start
)
{
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
if
(
itemRenderer
)
{
if
(
itemRenderer
)
{
itemRenderer
.
setStart
(
start
);
itemRenderer
.
setStart
(
start
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
...
@@ -410,13 +441,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
...
@@ -410,13 +441,13 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
* @returns true if the foreach exists
* @returns true if the foreach exists
*/
*/
this
.
updateNb
=
function
updateNb
(
id
,
nb
)
{
this
.
updateNb
=
function
updateNb
(
id
,
nb
)
{
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
if
(
itemRenderer
)
{
if
(
itemRenderer
)
{
itemRenderer
.
setNb
(
nb
);
itemRenderer
.
setNb
(
nb
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
...
@@ -425,201 +456,201 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
...
@@ -425,201 +456,201 @@ function BindPlugin(Store, Observable, Tools, DomUtils) {
* @returns true if the foreach exists
* @returns true if the foreach exists
*/
*/
this
.
refresh
=
function
refresh
(
id
)
{
this
.
refresh
=
function
refresh
(
id
)
{
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
var
itemRenderer
=
this
.
getItemRenderer
(
id
);
if
(
itemRenderer
)
{
if
(
itemRenderer
)
{
itemRenderer
.
render
();
itemRenderer
.
render
();
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Both ways binding between a dom node attributes and the model
* Both ways binding between a dom node attributes and the model
* @param {HTMLElement|SVGElement} node the dom node to apply the plugin to
* @param {HTMLElement|SVGElement} node the dom node to apply the plugin to
* @param {String} name the name of the property to look for in the model's value
* @param {String} name the name of the property to look for in the model's value
* @returns
* @returns
*/
*/
this
.
bind
=
function
bind
(
node
,
property
,
name
)
{
this
.
bind
=
function
bind
(
node
,
property
,
name
)
{
// Name can be unset if the value of a row is plain text
// Name can be unset if the value of a row is plain text
name
=
name
||
""
;
name
=
name
||
""
;
// In case of an array-like model the id is the index of the model's item to look for.
// In case of an array-like model the id is the index of the model's item to look for.
// The _id is added by the foreach function
// The _id is added by the foreach function
var
id
=
node
.
getAttribute
(
"
data-
"
+
this
.
plugins
.
name
+
"
_id
"
),
var
id
=
node
.
getAttribute
(
"
data-
"
+
this
.
plugins
.
name
+
"
_id
"
),
// Else, it is the first element of the following
// Else, it is the first element of the following
split
=
name
.
split
(
"
.
"
),
split
=
name
.
split
(
"
.
"
),
// So the index of the model is either id or the first element of split
// So the index of the model is either id or the first element of split
modelIdx
=
id
||
split
.
shift
(),
modelIdx
=
id
||
split
.
shift
(),
// And the name of the property to look for in the value is
// And the name of the property to look for in the value is
prop
=
id
?
name
:
split
.
join
(
"
.
"
),
prop
=
id
?
name
:
split
.
join
(
"
.
"
),
// Get the model's value
// Get the model's value
get
=
Tools
.
getNestedProperty
(
_model
.
get
(
modelIdx
),
prop
),
get
=
Tools
.
getNestedProperty
(
_model
.
get
(
modelIdx
),
prop
),
// When calling bind like bind:newBinding,param1, param2... we need to get them
// When calling bind like bind:newBinding,param1, param2... we need to get them
extraParam
=
Tools
.
toArray
(
arguments
).
slice
(
3
);
extraParam
=
Tools
.
toArray
(
arguments
).
slice
(
3
);
// 0 and false are acceptable falsy values
// 0 and false are acceptable falsy values
if
(
get
||
get
===
0
||
get
===
false
)
{
if
(
get
||
get
===
0
||
get
===
false
)
{
// If the binding hasn't been overriden
// If the binding hasn't been overriden
if
(
!
this
.
execBinding
.
apply
(
this
,
if
(
!
this
.
execBinding
.
apply
(
this
,
[
node
,
property
,
get
]
[
node
,
property
,
get
]
// Extra params are passed to the new binding too
// Extra params are passed to the new binding too
.
concat
(
extraParam
)))
{
.
concat
(
extraParam
)))
{
// Execute the default one which is a simple assignation
// Execute the default one which is a simple assignation
//node[property] = get;
//node[property] = get;
DomUtils
.
setAttribute
(
node
,
property
,
get
);
DomUtils
.
setAttribute
(
node
,
property
,
get
);
}
}
}
}
// Only watch for changes (double way data binding) if the binding
// Only watch for changes (double way data binding) if the binding
// has not been redefined
// has not been redefined
if
(
!
this
.
hasBinding
(
property
))
{
if
(
!
this
.
hasBinding
(
property
))
{
node
.
addEventListener
(
"
change
"
,
function
(
event
)
{
node
.
addEventListener
(
"
change
"
,
function
(
event
)
{
if
(
_model
.
has
(
modelIdx
))
{
if
(
_model
.
has
(
modelIdx
))
{
if
(
prop
)
{
if
(
prop
)
{
_model
.
update
(
modelIdx
,
name
,
node
[
property
]);
_model
.
update
(
modelIdx
,
name
,
node
[
property
]);
}
else
{
}
else
{
_model
.
set
(
modelIdx
,
node
[
property
]);
_model
.
set
(
modelIdx
,
node
[
property
]);
}
}
}
}
},
true
);
},
true
);
}
}
// Watch for changes
// Watch for changes
this
.
observers
[
modelIdx
]
=
this
.
observers
[
modelIdx
]
||
[];
this
.
observers
[
modelIdx
]
=
this
.
observers
[
modelIdx
]
||
[];
this
.
observers
[
modelIdx
].
push
(
_model
.
watchValue
(
modelIdx
,
function
(
value
)
{
this
.
observers
[
modelIdx
].
push
(
_model
.
watchValue
(
modelIdx
,
function
(
value
)
{
if
(
!
this
.
execBinding
.
apply
(
this
,
if
(
!
this
.
execBinding
.
apply
(
this
,
[
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
)]
[
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
)]
// passing extra params too
// passing extra params too
.
concat
(
extraParam
)))
{
.
concat
(
extraParam
)))
{
//node[property] = Tools.getNestedProperty(value, prop);
//node[property] = Tools.getNestedProperty(value, prop);
DomUtils
.
setAttribute
(
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
));
DomUtils
.
setAttribute
(
node
,
property
,
Tools
.
getNestedProperty
(
value
,
prop
));
}
}
},
this
));
},
this
));
};
};
/**
/**
* Set the node's value into the model, the name is the model's property
* Set the node's value into the model, the name is the model's property
* @private
* @private
* @param {HTMLElement|SVGElement} node
* @param {HTMLElement|SVGElement} node
* @returns true if the property is added
* @returns true if the property is added
*/
*/
this
.
set
=
function
set
(
node
)
{
this
.
set
=
function
set
(
node
)
{
if
(
DomUtils
.
isAcceptedType
(
node
)
&&
node
.
name
)
{
if
(
DomUtils
.
isAcceptedType
(
node
)
&&
node
.
name
)
{
_model
.
set
(
node
.
name
,
node
.
value
);
_model
.
set
(
node
.
name
,
node
.
value
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
this
.
getItemIndex
=
function
getElementId
(
dom
)
{
this
.
getItemIndex
=
function
getElementId
(
dom
)
{
var
dataset
=
DomUtils
.
getDataset
(
dom
);
var
dataset
=
DomUtils
.
getDataset
(
dom
);
if
(
dataset
&&
typeof
dataset
[
this
.
plugins
.
name
+
"
_id
"
]
!=
"
undefined
"
)
{
if
(
dataset
&&
typeof
dataset
[
this
.
plugins
.
name
+
"
_id
"
]
!=
"
undefined
"
)
{
return
+
dataset
[
this
.
plugins
.
name
+
"
_id
"
];
return
+
dataset
[
this
.
plugins
.
name
+
"
_id
"
];
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Prevents the submit and set the model with all form's inputs
* Prevents the submit and set the model with all form's inputs
* @param {HTMLFormElement} for
m
* @param {HTMLFormElement} DOMfro
m
* @returns true if valid form
* @returns true if valid form
*/
*/
this
.
form
=
function
form
(
form
)
{
this
.
form
=
function
form
(
DOM
form
)
{
if
(
form
&&
form
.
nodeName
==
"
FORM
"
)
{
if
(
DOMform
&&
DOM
form
.
nodeName
==
"
FORM
"
)
{
var
that
=
this
;
var
that
=
this
;
form
.
addEventListener
(
"
submit
"
,
function
(
event
)
{
DOM
form
.
addEventListener
(
"
submit
"
,
function
(
event
)
{
Tools
.
toArray
(
form
.
querySelectorAll
(
"
[name]
"
)).
forEach
(
that
.
set
,
that
);
Tools
.
toArray
(
DOM
form
.
querySelectorAll
(
"
[name]
"
)).
forEach
(
that
.
set
,
that
);
event
.
preventDefault
();
event
.
preventDefault
();
},
true
);
},
true
);
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Add a new way to handle a binding
* Add a new way to handle a binding
* @param {String} name of the binding
* @param {String} name of the binding
* @param {Function} binding the function to handle the binding
* @param {Function} binding the function to handle the binding
* @returns
* @returns
*/
*/
this
.
addBinding
=
function
addBinding
(
name
,
binding
)
{
this
.
addBinding
=
function
addBinding
(
name
,
binding
)
{
if
(
name
&&
typeof
name
==
"
string
"
&&
typeof
binding
==
"
function
"
)
{
if
(
name
&&
typeof
name
==
"
string
"
&&
typeof
binding
==
"
function
"
)
{
_bindings
[
name
]
=
binding
;
_bindings
[
name
]
=
binding
;
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Execute a binding
* Execute a binding
* Only used by the plugin
* Only used by the plugin
* @private
* @private
* @param {HTMLElement} node the dom node on which to execute the binding
* @param {HTMLElement} node the dom node on which to execute the binding
* @param {String} name the name of the binding
* @param {String} name the name of the binding
* @param {Any type} value the value to pass to the function
* @param {Any type} value the value to pass to the function
* @returns
* @returns
*/
*/
this
.
execBinding
=
function
execBinding
(
node
,
name
)
{
this
.
execBinding
=
function
execBinding
(
node
,
name
)
{
if
(
this
.
hasBinding
(
name
))
{
if
(
this
.
hasBinding
(
name
))
{
_bindings
[
name
].
apply
(
node
,
Array
.
prototype
.
slice
.
call
(
arguments
,
2
));
_bindings
[
name
].
apply
(
node
,
Array
.
prototype
.
slice
.
call
(
arguments
,
2
));
return
true
;
return
true
;
}
else
{
}
else
{
return
false
;
return
false
;
}
}
};
};
/**
/**
* Check if the binding exists
* Check if the binding exists
* @private
* @private
* @param {String} name the name of the binding
* @param {String} name the name of the binding
* @returns
* @returns
*/
*/
this
.
hasBinding
=
function
hasBinding
(
name
)
{
this
.
hasBinding
=
function
hasBinding
(
name
)
{
return
_bindings
.
hasOwnProperty
(
name
);
return
_bindings
.
hasOwnProperty
(
name
);
};
};
/**
/**
* Get a binding
* Get a binding
* For debugging only
* For debugging only
* @private
* @private
* @param {String} name the name of the binding
* @param {String} name the name of the binding
* @returns
* @returns
*/
*/
this
.
getBinding
=
function
getBinding
(
name
)
{
this
.
getBinding
=
function
getBinding
(
name
)
{
return
_bindings
[
name
];
return
_bindings
[
name
];
};
};
/**
/**
* Add multiple binding at once
* Add multiple binding at once
* @param {Object} list the list of bindings to add
* @param {Object} list the list of bindings to add
* @returns
* @returns
*/
*/
this
.
addBindings
=
function
addBindings
(
list
)
{
this
.
addBindings
=
function
addBindings
(
list
)
{
return
Tools
.
loop
(
list
,
function
(
binding
,
name
)
{
return
Tools
.
loop
(
list
,
function
(
binding
,
name
)
{
this
.
addBinding
(
name
,
binding
);
this
.
addBinding
(
name
,
binding
);
},
this
);
},
this
);
};
};
// Inits the model
// Inits the model
this
.
setModel
(
$model
);
this
.
setModel
(
$model
);
// Inits bindings
// Inits bindings
this
.
addBindings
(
$bindings
);
this
.
addBindings
(
$bindings
);
};
};
});
});
examples/olives/bower_components/olives/src/DomUtils.js
View file @
9df98e41
...
@@ -6,6 +6,8 @@
...
@@ -6,6 +6,8 @@
define
([
"
Tools
"
],
function
(
Tools
)
{
define
([
"
Tools
"
],
function
(
Tools
)
{
"
use strict
"
;
return
{
return
{
/**
/**
* Returns a NodeList including the given dom node,
* Returns a NodeList including the given dom node,
...
...
examples/olives/bower_components/olives/src/Event.plugin.js
View file @
9df98e41
...
@@ -14,121 +14,123 @@ define(["DomUtils"],
...
@@ -14,121 +14,123 @@ define(["DomUtils"],
*/
*/
function
EventPlugin
(
Utils
)
{
function
EventPlugin
(
Utils
)
{
/**
"
use strict
"
;
* The event plugin constructor.
* ex: new EventPlugin({method: function(){} ...}, false);
/**
* @param {Object} the object that has the event handling methods
* The event plugin constructor.
* @param {Boolean} $isMobile if the event handler has to map with touch events
* ex: new EventPlugin({method: function(){} ...}, false);
*/
* @param {Object} the object that has the event handling methods
return
function
EventPluginConstructor
(
$parent
,
$isMobile
)
{
* @param {Boolean} $isMobile if the event handler has to map with touch events
*/
/**
return
function
EventPluginConstructor
(
$parent
,
$isMobile
)
{
* The parent callback
* @private
/**
*/
* The parent callback
var
_parent
=
null
,
* @private
*/
/**
var
_parent
=
null
,
* The mapping object.
* @private
/**
*/
* The mapping object.
_map
=
{
* @private
"
mousedown
"
:
"
touchstart
"
,
*/
"
mouseup
"
:
"
touchend
"
,
_map
=
{
"
mousemove
"
:
"
touchmove
"
"
mousedown
"
:
"
touchstart
"
,
},
"
mouseup
"
:
"
touchend
"
,
"
mousemove
"
:
"
touchmove
"
/**
},
* Is touch device.
* @private
/**
*/
* Is touch device.
_isMobile
=
!!
$isMobile
;
* @private
*/
/**
_isMobile
=
!!
$isMobile
;
* Add mapped event listener (for testing purpose).
* @private
/**
*/
* Add mapped event listener (for testing purpose).
this
.
addEventListener
=
function
addEventListener
(
node
,
event
,
callback
,
useCapture
)
{
* @private
node
.
addEventListener
(
this
.
map
(
event
),
callback
,
!!
useCapture
);
*/
};
this
.
addEventListener
=
function
addEventListener
(
node
,
event
,
callback
,
useCapture
)
{
node
.
addEventListener
(
this
.
map
(
event
),
callback
,
!!
useCapture
);
/**
};
* Listen to DOM events.
* @param {Object} node DOM node
/**
* @param {String} name event's name
* Listen to DOM events.
* @param {String} listener callback's name
* @param {Object} node DOM node
* @param {String} useCapture string
* @param {String} name event's name
*/
* @param {String} listener callback's name
this
.
listen
=
function
listen
(
node
,
name
,
listener
,
useCapture
)
{
* @param {String} useCapture string
this
.
addEventListener
(
node
,
name
,
function
(
e
){
*/
_parent
[
listener
].
call
(
_parent
,
e
,
node
);
this
.
listen
=
function
listen
(
node
,
name
,
listener
,
useCapture
)
{
},
!!
useCapture
);
this
.
addEventListener
(
node
,
name
,
function
(
e
){
};
_parent
[
listener
].
call
(
_parent
,
e
,
node
);
},
!!
useCapture
);
/**
};
* Delegate the event handling to a parent DOM element
* @param {Object} node DOM node
/**
* @param {String} selector CSS3 selector to the element that listens to the event
* Delegate the event handling to a parent DOM element
* @param {String} name event's name
* @param {Object} node DOM node
* @param {String} listener callback's name
* @param {String} selector CSS3 selector to the element that listens to the event
* @param {String} useCapture string
* @param {String} name event's name
*/
* @param {String} listener callback's name
this
.
delegate
=
function
delegate
(
node
,
selector
,
name
,
listener
,
useCapture
)
{
* @param {String} useCapture string
this
.
addEventListener
(
node
,
name
,
function
(
event
){
*/
if
(
Utils
.
matches
(
node
,
selector
,
event
.
target
))
{
this
.
delegate
=
function
delegate
(
node
,
selector
,
name
,
listener
,
useCapture
)
{
_parent
[
listener
].
call
(
_parent
,
event
,
node
);
this
.
addEventListener
(
node
,
name
,
function
(
event
){
}
if
(
Utils
.
matches
(
node
,
selector
,
event
.
target
))
{
},
!!
useCapture
);
_parent
[
listener
].
call
(
_parent
,
event
,
node
);
};
}
},
!!
useCapture
);
/**
};
* Get the parent object.
* @return {Object} the parent object
/**
*/
* Get the parent object.
this
.
getParent
=
function
getParent
()
{
* @return {Object} the parent object
return
_parent
;
*/
};
this
.
getParent
=
function
getParent
()
{
return
_parent
;
/**
};
* Set the parent object.
* The parent object is an object which the functions are called by node listeners.
/**
* @param {Object} the parent object
* Set the parent object.
* @return true if object has been set
* The parent object is an object which the functions are called by node listeners.
*/
* @param {Object} the parent object
this
.
setParent
=
function
setParent
(
parent
)
{
* @return true if object has been set
if
(
parent
instanceof
Object
){
*/
_parent
=
parent
;
this
.
setParent
=
function
setParent
(
parent
)
{
return
true
;
if
(
parent
instanceof
Object
){
}
_parent
=
parent
;
return
false
;
return
true
;
};
}
return
false
;
/**
};
* Get event mapping.
* @param {String} event's name
/**
* @return the mapped event's name
* Get event mapping.
*/
* @param {String} event's name
this
.
map
=
function
map
(
name
)
{
* @return the mapped event's name
return
_isMobile
?
(
_map
[
name
]
||
name
)
:
name
;
*/
};
this
.
map
=
function
map
(
name
)
{
return
_isMobile
?
(
_map
[
name
]
||
name
)
:
name
;
/**
};
* Set event mapping.
* @param {String} event's name
/**
* @param {String} event's value
* Set event mapping.
* @return true if mapped
* @param {String} event's name
*/
* @param {String} event's value
this
.
setMap
=
function
setMap
(
name
,
value
)
{
* @return true if mapped
if
(
typeof
name
==
"
string
"
&&
*/
typeof
value
==
"
string
"
)
{
this
.
setMap
=
function
setMap
(
name
,
value
)
{
_map
[
name
]
=
value
;
if
(
typeof
name
==
"
string
"
&&
return
true
;
typeof
value
==
"
string
"
)
{
}
_map
[
name
]
=
value
;
return
false
;
return
true
;
};
}
return
false
;
//init
};
this
.
setParent
(
$parent
);
};
//init
this
.
setParent
(
$parent
);
};
});
});
examples/olives/bower_components/olives/src/LocalStore.js
View file @
9df98e41
...
@@ -15,6 +15,8 @@ define(["Store", "Tools"],
...
@@ -15,6 +15,8 @@ define(["Store", "Tools"],
*/
*/
function
LocalStore
(
Store
,
Tools
)
{
function
LocalStore
(
Store
,
Tools
)
{
"
use strict
"
;
function
LocalStoreConstructor
()
{
function
LocalStoreConstructor
()
{
/**
/**
...
@@ -96,7 +98,7 @@ function LocalStore(Store, Tools) {
...
@@ -96,7 +98,7 @@ function LocalStore(Store, Tools) {
return
function
LocalStoreFactory
(
init
)
{
return
function
LocalStoreFactory
(
init
)
{
LocalStoreConstructor
.
prototype
=
new
Store
(
init
);
LocalStoreConstructor
.
prototype
=
new
Store
(
init
);
return
new
LocalStoreConstructor
;
return
new
LocalStoreConstructor
()
;
};
};
});
});
examples/olives/bower_components/olives/src/OObject.js
View file @
9df98e41
...
@@ -13,179 +13,185 @@ define(["StateMachine", "Store", "Plugins", "DomUtils", "Tools"],
...
@@ -13,179 +13,185 @@ define(["StateMachine", "Store", "Plugins", "DomUtils", "Tools"],
*/
*/
function
OObject
(
StateMachine
,
Store
,
Plugins
,
DomUtils
,
Tools
)
{
function
OObject
(
StateMachine
,
Store
,
Plugins
,
DomUtils
,
Tools
)
{
return
function
OObjectConstructor
(
otherStore
)
{
"
use strict
"
;
/**
return
function
OObjectConstructor
(
otherStore
)
{
* This function creates the dom of the UI from its template
* It then queries the dom for data- attributes
/**
* It can't be executed if the template is not set
* This function creates the dom of the UI from its template
* @private
* It then queries the dom for data- attributes
*/
* It can't be executed if the template is not set
var
render
=
function
render
(
UI
)
{
* @private
*/
// The place where the template will be created
var
render
=
function
render
(
UI
)
{
// is either the currentPlace where the node is placed
// or a temporary div
// The place where the template will be created
var
baseNode
=
_currentPlace
||
document
.
createElement
(
"
div
"
);
// is either the currentPlace where the node is placed
// or a temporary div
// If the template is set
var
baseNode
=
_currentPlace
||
document
.
createElement
(
"
div
"
);
if
(
UI
.
template
)
{
// In this function, the thisObject is the UI's prototype
// If the template is set
// UI is the UI that has OObject as prototype
if
(
UI
.
template
)
{
if
(
typeof
UI
.
template
==
"
string
"
)
{
// In this function, the thisObject is the UI's prototype
// Let the browser do the parsing, can't be faster & easier.
// UI is the UI that has OObject as prototype
baseNode
.
innerHTML
=
UI
.
template
.
trim
();
if
(
typeof
UI
.
template
==
"
string
"
)
{
}
else
if
(
DomUtils
.
isAcceptedType
(
UI
.
template
))
{
// Let the browser do the parsing, can't be faster & easier.
// If it's already an HTML element
baseNode
.
innerHTML
=
UI
.
template
.
trim
();
baseNode
.
appendChild
(
UI
.
template
);
}
else
if
(
DomUtils
.
isAcceptedType
(
UI
.
template
))
{
}
// If it's already an HTML element
baseNode
.
appendChild
(
UI
.
template
);
// The UI must be placed in a unique dom node
}
// If not, there can't be multiple UIs placed in the same parentNode
// as it wouldn't be possible to know which node would belong to which UI
// The UI must be placed in a unique dom node
// This is probably a DOM limitation.
// If not, there can't be multiple UIs placed in the same parentNode
if
(
baseNode
.
childNodes
.
length
>
1
)
{
// as it wouldn't be possible to know which node would belong to which UI
throw
Error
(
"
UI.template should have only one parent node
"
);
// This is probably a DOM limitation.
}
else
{
if
(
baseNode
.
childNodes
.
length
>
1
)
{
UI
.
dom
=
baseNode
.
childNodes
[
0
];
throw
new
Error
(
"
UI.template should have only one parent node
"
);
}
}
else
{
UI
.
dom
=
baseNode
.
childNodes
[
0
];
UI
.
plugins
.
apply
(
UI
.
dom
);
}
}
else
{
UI
.
plugins
.
apply
(
UI
.
dom
);
// An explicit message I hope
throw
Error
(
"
UI.template must be set prior to render
"
);
}
else
{
}
// An explicit message I hope
},
throw
new
Error
(
"
UI.template must be set prior to render
"
);
}
/**
},
* This function appends the dom tree to the given dom node.
* This dom node should be somewhere in the dom of the application
/**
* @private
* This function appends the dom tree to the given dom node.
*/
* This dom node should be somewhere in the dom of the application
place
=
function
place
(
UI
,
place
,
beforeNode
)
{
* @private
if
(
place
)
{
*/
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
place
=
function
place
(
UI
,
DOMplace
,
beforeNode
)
{
beforeNode
?
place
.
insertBefore
(
UI
.
dom
,
beforeNode
)
:
place
.
appendChild
(
UI
.
dom
);
if
(
DOMplace
)
{
// Also save the new place, so next renderings
// IE (until 9) apparently fails to appendChild when insertBefore's second argument is null, hence this.
// will be made inside it
if
(
beforeNode
)
{
_currentPlace
=
place
;
DOMplace
.
insertBefore
(
UI
.
dom
,
beforeNode
);
}
}
else
{
},
DOMplace
.
appendChild
(
UI
.
dom
);
}
/**
// Also save the new place, so next renderings
* Does rendering & placing in one function
// will be made inside it
* @private
_currentPlace
=
DOMplace
;
*/
}
renderNPlace
=
function
renderNPlace
(
UI
,
dom
)
{
},
render
(
UI
);
place
.
apply
(
null
,
Tools
.
toArray
(
arguments
));
/**
},
* Does rendering & placing in one function
* @private
/**
*/
* This stores the current place
renderNPlace
=
function
renderNPlace
(
UI
,
dom
)
{
* If this is set, this is the place where new templates
render
(
UI
);
* will be appended
place
.
apply
(
null
,
Tools
.
toArray
(
arguments
));
* @private
},
*/
_currentPlace
=
null
,
/**
* This stores the current place
/**
* If this is set, this is the place where new templates
* The UI's stateMachine.
* will be appended
* Much better than if(stuff) do(stuff) else if (!stuff and stuff but not stouff) do (otherstuff)
* @private
* Please open an issue if you want to propose a better one
*/
* @private
_currentPlace
=
null
,
*/
_stateMachine
=
new
StateMachine
(
"
Init
"
,
{
/**
"
Init
"
:
[[
"
render
"
,
render
,
this
,
"
Rendered
"
],
* The UI's stateMachine.
[
"
place
"
,
renderNPlace
,
this
,
"
Rendered
"
]],
* Much better than if(stuff) do(stuff) else if (!stuff and stuff but not stouff) do (otherstuff)
"
Rendered
"
:
[[
"
place
"
,
place
,
this
],
* Please open an issue if you want to propose a better one
[
"
render
"
,
render
,
this
]]
* @private
});
*/
_stateMachine
=
new
StateMachine
(
"
Init
"
,
{
/**
"
Init
"
:
[[
"
render
"
,
render
,
this
,
"
Rendered
"
],
* The UI's Store
[
"
place
"
,
renderNPlace
,
this
,
"
Rendered
"
]],
* It has set/get/del/has/watch/unwatch methods
"
Rendered
"
:
[[
"
place
"
,
place
,
this
],
* @see Emily's doc for more info on how it works.
[
"
render
"
,
render
,
this
]]
*/
});
this
.
model
=
otherStore
instanceof
Store
?
otherStore
:
new
Store
;
/**
/**
* The UI's Store
* The module that will manage the plugins for this UI
* It has set/get/del/has/watch/unwatch methods
* @see Olives/Plugins' doc for more info on how it works.
* @see Emily's doc for more info on how it works.
*/
*/
this
.
plugins
=
new
Plugins
();
this
.
model
=
otherStore
instanceof
Store
?
otherStore
:
new
Store
();
/**
/**
* Describes the template, can either be like "<p></p>" or HTMLElements
* The module that will manage the plugins for this UI
* @type string or HTMLElement|SVGElement
* @see Olives/Plugins' doc for more info on how it works.
*/
*/
this
.
template
=
null
;
this
.
plugins
=
new
Plugins
();
/**
/**
* This will hold the dom nodes built from the template.
* Describes the template, can either be like "<p></p>" or HTMLElements
*/
* @type string or HTMLElement|SVGElement
this
.
dom
=
null
;
*/
this
.
template
=
null
;
/**
* Place the UI in a given dom node
/**
* @param node the node on which to append the UI
* This will hold the dom nodes built from the template.
* @param beforeNode the dom before which to append the UI
*/
*/
this
.
dom
=
null
;
this
.
place
=
function
place
(
node
,
beforeNode
)
{
_stateMachine
.
event
(
"
place
"
,
this
,
node
,
beforeNode
);
/**
};
* Place the UI in a given dom node
* @param node the node on which to append the UI
/**
* @param beforeNode the dom before which to append the UI
* Renders the template to dom nodes and applies the plugins on it
*/
* It requires the template to be set first
this
.
place
=
function
place
(
node
,
beforeNode
)
{
*/
_stateMachine
.
event
(
"
place
"
,
this
,
node
,
beforeNode
);
this
.
render
=
function
render
()
{
};
_stateMachine
.
event
(
"
render
"
,
this
);
};
/**
* Renders the template to dom nodes and applies the plugins on it
/**
* It requires the template to be set first
* Set the UI's template from a DOM element
*/
* @param {HTMLElement|SVGElement} dom the dom element that'll become the template of the UI
this
.
render
=
function
render
()
{
* @returns true if dom is an HTMLElement|SVGElement
_stateMachine
.
event
(
"
render
"
,
this
);
*/
};
this
.
setTemplateFromDom
=
function
setTemplateFromDom
(
dom
)
{
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
/**
this
.
template
=
dom
;
* Set the UI's template from a DOM element
return
true
;
* @param {HTMLElement|SVGElement} dom the dom element that'll become the template of the UI
}
else
{
* @returns true if dom is an HTMLElement|SVGElement
return
false
;
*/
}
this
.
setTemplateFromDom
=
function
setTemplateFromDom
(
dom
)
{
};
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
this
.
template
=
dom
;
/**
return
true
;
* Transforms dom nodes into a UI.
}
else
{
* It basically does a setTemplateFromDOM, then a place
return
false
;
* It's a helper function
}
* @param {HTMLElement|SVGElement} node the dom to transform to a UI
};
* @returns true if dom is an HTMLElement|SVGElement
*/
/**
this
.
alive
=
function
alive
(
dom
)
{
* Transforms dom nodes into a UI.
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
* It basically does a setTemplateFromDOM, then a place
this
.
setTemplateFromDom
(
dom
);
* It's a helper function
this
.
place
(
dom
.
parentNode
,
dom
.
nextElementSibling
);
* @param {HTMLElement|SVGElement} node the dom to transform to a UI
return
true
;
* @returns true if dom is an HTMLElement|SVGElement
}
else
{
*/
return
false
;
this
.
alive
=
function
alive
(
dom
)
{
}
if
(
DomUtils
.
isAcceptedType
(
dom
))
{
this
.
setTemplateFromDom
(
dom
);
};
this
.
place
(
dom
.
parentNode
,
dom
.
nextElementSibling
);
return
true
;
/**
}
else
{
* Get the current dom node where the UI is placed.
return
false
;
* for debugging purpose
}
* @private
* @return {HTMLElement} node the dom where the UI is placed.
};
*/
this
.
getCurrentPlace
=
function
(){
/**
return
_currentPlace
;
* Get the current dom node where the UI is placed.
};
* for debugging purpose
* @private
};
* @return {HTMLElement} node the dom where the UI is placed.
*/
this
.
getCurrentPlace
=
function
(){
return
_currentPlace
;
};
};
});
});
examples/olives/bower_components/olives/src/Place.plugin.js
View file @
9df98e41
...
@@ -12,77 +12,79 @@ define(["OObject", "Tools"],
...
@@ -12,77 +12,79 @@ define(["OObject", "Tools"],
*/
*/
function
PlacePlugin
(
OObject
,
Tools
)
{
function
PlacePlugin
(
OObject
,
Tools
)
{
/**
"
use strict
"
;
* Intilialize a Place.plugin with a list of OObjects
* @param {Object} $uis a list of OObjects such as:
* {
* "header": new OObject(),
* "list": new OObject()
* }
* @Constructor
*/
return
function
PlacePluginConstructor
(
$uis
)
{
/**
/**
* The list of uis currently set in this place plugin
* Intilialize a Place.plugin with a list of OObjects
* @private
* @param {Object} $uis a list of OObjects such as:
*/
* {
var
_uis
=
{};
* "header": new OObject(),
* "list": new OObject()
* }
* @Constructor
*/
return
function
PlacePluginConstructor
(
$uis
)
{
/**
/**
* Attach an OObject to this DOM element
* The list of uis currently set in this place plugin
* @param {HTML|SVGElement} node the dom node where to attach the OObject
* @private
* @param {String} the name of the OObject to attach
*/
* @throws {NoSuchOObject} an error if there's no OObject for the given name
var
_uis
=
{};
*/
this
.
place
=
function
place
(
node
,
name
)
{
if
(
_uis
[
name
]
instanceof
OObject
)
{
_uis
[
name
].
place
(
node
);
}
else
{
throw
new
Error
(
name
+
"
is not an OObject UI in place:
"
+
name
);
}
};
/**
/**
* Add an OObject that can be attached to a dom element
* Attach an OObject to this DOM element
* @param {String} the name of the OObject to add to the list
* @param {HTML|SVGElement} node the dom node where to attach the OObject
* @param {OObject} ui the OObject to add the list
* @param {String} the name of the OObject to attach
* @returns {Boolean} true if the OObject was added
* @throws {NoSuchOObject} an error if there's no OObject for the given name
*/
*/
this
.
set
=
function
set
(
name
,
ui
)
{
this
.
place
=
function
place
(
node
,
name
)
{
if
(
typeof
name
==
"
string
"
&&
ui
instanceof
OObject
)
{
if
(
_uis
[
name
]
instanceof
OObject
)
{
_uis
[
name
]
=
ui
;
_uis
[
name
].
place
(
node
);
return
true
;
}
else
{
}
else
{
throw
new
Error
(
name
+
"
is not an OObject UI in place:
"
+
name
);
return
false
;
}
}
};
};
/**
/**
* Add multiple dom elements at once
* Add an OObject that can be attached to a dom element
* @param {Object} $uis a list of OObjects such as:
* @param {String} the name of the OObject to add to the list
* {
* @param {OObject} ui the OObject to add the list
* "header": new OObject(),
* @returns {Boolean} true if the OObject was added
* "list": new OObject()
*/
* }
this
.
set
=
function
set
(
name
,
ui
)
{
*/
if
(
typeof
name
==
"
string
"
&&
ui
instanceof
OObject
)
{
this
.
setAll
=
function
setAll
(
uis
)
{
_uis
[
name
]
=
ui
;
Tools
.
loop
(
uis
,
function
(
ui
,
name
)
{
return
true
;
this
.
set
(
name
,
ui
);
}
else
{
},
this
);
return
false
;
};
}
};
/**
/**
* Returns an OObject from the list given its name
* Add multiple dom elements at once
* @param {String} the name of the OObject to get
* @param {Object} $uis a list of OObjects such as:
* @returns {OObject} OObject for the given name
* {
*/
* "header": new OObject(),
this
.
get
=
function
get
(
name
)
{
* "list": new OObject()
return
_uis
[
name
];
* }
};
*/
this
.
setAll
=
function
setAll
(
uis
)
{
Tools
.
loop
(
uis
,
function
(
ui
,
name
)
{
this
.
set
(
name
,
ui
);
},
this
);
};
this
.
setAll
(
$uis
);
/**
* Returns an OObject from the list given its name
* @param {String} the name of the OObject to get
* @returns {OObject} OObject for the given name
*/
this
.
get
=
function
get
(
name
)
{
return
_uis
[
name
];
};
};
this
.
setAll
(
$uis
);
};
});
});
examples/olives/bower_components/olives/src/Plugins.js
View file @
9df98e41
...
@@ -17,6 +17,8 @@ define(["Tools", "DomUtils"],
...
@@ -17,6 +17,8 @@ define(["Tools", "DomUtils"],
*/
*/
function
Plugins
(
Tools
,
DomUtils
)
{
function
Plugins
(
Tools
,
DomUtils
)
{
"
use strict
"
;
return
function
PluginsConstructor
(
$plugins
)
{
return
function
PluginsConstructor
(
$plugins
)
{
/**
/**
...
...
examples/olives/bower_components/olives/src/SocketIOTransport.js
View file @
9df98e41
...
@@ -12,6 +12,8 @@ define(["Observable", "Tools"],
...
@@ -12,6 +12,8 @@ define(["Observable", "Tools"],
*/
*/
function
SocketIOTransport
(
Observable
,
Tools
)
{
function
SocketIOTransport
(
Observable
,
Tools
)
{
"
use strict
"
;
/**
/**
* Defines the SocketIOTransport
* Defines the SocketIOTransport
* @private
* @private
...
@@ -47,7 +49,7 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -47,7 +49,7 @@ function SocketIOTransport(Observable, Tools) {
*/
*/
this
.
getSocket
=
function
getSocket
()
{
this
.
getSocket
=
function
getSocket
()
{
return
_socket
;
return
_socket
;
}
,
}
;
/**
/**
* Subscribe to a socket event
* Subscribe to a socket event
...
@@ -56,7 +58,7 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -56,7 +58,7 @@ function SocketIOTransport(Observable, Tools) {
*/
*/
this
.
on
=
function
on
(
event
,
func
)
{
this
.
on
=
function
on
(
event
,
func
)
{
return
_socket
.
on
(
event
,
func
);
return
_socket
.
on
(
event
,
func
);
}
,
}
;
/**
/**
* Subscribe to a socket event but disconnect as soon as it fires.
* Subscribe to a socket event but disconnect as soon as it fires.
...
@@ -95,15 +97,17 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -95,15 +97,17 @@ function SocketIOTransport(Observable, Tools) {
* @param {Object} scope the scope in which to execute the callback
* @param {Object} scope the scope in which to execute the callback
*/
*/
this
.
request
=
function
request
(
channel
,
data
,
func
,
scope
)
{
this
.
request
=
function
request
(
channel
,
data
,
func
,
scope
)
{
if
(
typeof
channel
==
"
string
"
if
(
typeof
channel
==
"
string
"
&&
&&
typeof
data
!=
"
undefined
"
)
{
typeof
data
!=
"
undefined
"
)
{
var
reqData
=
{
var
reqData
=
{
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
data
:
data
data
:
data
},
},
boundCallback
=
function
()
{
boundCallback
=
function
()
{
func
&&
func
.
apply
(
scope
||
null
,
arguments
);
if
(
func
)
{
func
.
apply
(
scope
||
null
,
arguments
);
}
};
};
this
.
once
(
reqData
.
eventId
,
boundCallback
);
this
.
once
(
reqData
.
eventId
,
boundCallback
);
...
@@ -125,9 +129,9 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -125,9 +129,9 @@ function SocketIOTransport(Observable, Tools) {
* @returns
* @returns
*/
*/
this
.
listen
=
function
listen
(
channel
,
data
,
func
,
scope
)
{
this
.
listen
=
function
listen
(
channel
,
data
,
func
,
scope
)
{
if
(
typeof
channel
==
"
string
"
if
(
typeof
channel
==
"
string
"
&&
&&
typeof
data
!=
"
undefined
"
typeof
data
!=
"
undefined
"
&&
&&
typeof
func
==
"
function
"
)
{
typeof
func
==
"
function
"
)
{
var
reqData
=
{
var
reqData
=
{
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
eventId
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1
e6
),
...
@@ -135,7 +139,9 @@ function SocketIOTransport(Observable, Tools) {
...
@@ -135,7 +139,9 @@ function SocketIOTransport(Observable, Tools) {
keepAlive
:
true
keepAlive
:
true
},
},
boundCallback
=
function
()
{
boundCallback
=
function
()
{
func
&&
func
.
apply
(
scope
||
null
,
arguments
);
if
(
func
)
{
func
.
apply
(
scope
||
null
,
arguments
);
}
},
},
that
=
this
;
that
=
this
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment