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
Eugene Shen
todomvc
Commits
0b69fdca
Commit
0b69fdca
authored
Oct 20, 2011
by
addyosmani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
merging fidel todo app
parent
7d8888e7
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1995 additions
and
0 deletions
+1995
-0
todo-example/fidel/app.js
todo-example/fidel/app.js
+132
-0
todo-example/fidel/images/destroy.png
todo-example/fidel/images/destroy.png
+0
-0
todo-example/fidel/index.html
todo-example/fidel/index.html
+86
-0
todo-example/fidel/stylesheets/todos.css
todo-example/fidel/stylesheets/todos.css
+532
-0
todo-example/fidel/vendor/fidel.js
todo-example/fidel/vendor/fidel.js
+268
-0
todo-example/fidel/vendor/jquery-1.6.4.min.js
todo-example/fidel/vendor/jquery-1.6.4.min.js
+4
-0
todo-example/fidel/vendor/json2.js
todo-example/fidel/vendor/json2.js
+481
-0
todo-example/fidel/vendor/live.js
todo-example/fidel/vendor/live.js
+233
-0
todo-example/fidel/vendor/todos.js
todo-example/fidel/vendor/todos.js
+259
-0
No files found.
todo-example/fidel/app.js
0 → 100644
View file @
0b69fdca
var
todoStore
=
(
function
()
{
return
{
get
:
function
()
{
var
d
=
localStorage
.
getItem
(
'
fidel.todos
'
);
var
todos
=
{};
if
(
d
)
{
d
=
JSON
.
parse
(
d
);
for
(
var
key
in
d
)
{
todos
[
key
]
=
new
Todo
(
d
[
key
]);
}
}
return
todos
;
},
save
:
function
(
todos
)
{
localStorage
.
setItem
(
'
fidel.todos
'
,
JSON
.
stringify
(
todos
));
}
};
})();
var
Todo
=
Fidel
.
Class
.
extend
({
defaults
:
{
name
:
"
empty todo...
"
,
done
:
false
,
order
:
0
},
init
:
function
()
{
},
toggleDone
:
function
()
{
this
.
done
=
!
this
.
done
;
}
});
var
TodoView
=
Fidel
.
ViewController
.
extend
({
templates
:
{
item
:
"
#item-template
"
,
stats
:
'
#stats-template
'
},
events
:
{
'
keypress input[type="text"]
'
:
'
addOnEnter
'
,
'
click .check
'
:
'
complete
'
},
init
:
function
()
{
this
.
todos
=
todoStore
.
get
();
this
.
renderAll
();
},
addOnEnter
:
function
(
e
)
{
if
(
e
.
keyCode
==
13
)
this
.
add
();
},
add
:
function
()
{
var
name
=
this
.
input
.
val
();
this
.
input
.
val
(
''
);
var
todo
=
new
Todo
({
name
:
name
,
order
:
this
.
taskCount
});
this
.
taskCount
++
;
this
.
todos
[
todo
.
guid
]
=
todo
;
this
.
save
();
var
tmp
=
this
.
template
(
this
.
templates
.
item
,
{
todo
:
todo
});
this
.
todosContainer
.
prepend
(
tmp
);
this
.
renderStats
();
},
save
:
function
()
{
todoStore
.
save
(
this
.
todos
);
},
sortTasks
:
function
()
{
var
sorted
=
[];
for
(
var
key
in
this
.
todos
)
{
sorted
.
push
(
this
.
todos
[
key
]);
}
sorted
.
sort
(
function
(
a
,
b
)
{
return
(
b
.
order
-
a
.
order
);
});
return
sorted
;
},
renderAll
:
function
()
{
var
html
=
[];
var
todos
=
this
.
sortTasks
();
this
.
taskCount
=
todos
.
length
;
for
(
var
i
=
0
,
c
=
todos
.
length
;
i
<
c
;
i
++
)
{
var
todo
=
todos
[
i
];
var
tmp
=
this
.
template
(
this
.
templates
.
item
,
{
todo
:
todo
});
html
.
push
(
tmp
);
}
this
.
todosContainer
.
html
(
html
.
join
(
''
));
this
.
renderStats
();
},
renderStats
:
function
()
{
var
todos
=
this
.
sortTasks
();
var
data
=
{
total
:
todos
.
length
,
remaining
:
0
,
done
:
0
};
for
(
var
i
=
0
,
c
=
todos
.
length
;
i
<
c
;
i
++
)
{
var
todo
=
todos
[
i
];
if
(
todo
.
done
)
data
.
done
++
;
else
data
.
remaining
++
;
}
this
.
render
(
'
stats
'
,
data
,
this
.
statsContainer
);
},
complete
:
function
(
e
)
{
var
complete
=
(
e
.
target
.
value
==
"
on
"
);
var
el
=
$
(
e
.
target
);
el
.
parents
(
'
li
'
).
toggleClass
(
'
done
'
);
var
todoId
=
el
.
parents
(
'
li
'
).
attr
(
'
data-todoid
'
);
this
.
todos
[
todoId
].
toggleDone
();
this
.
save
();
this
.
renderStats
();
},
clearCompleted
:
function
()
{
var
completedTodos
=
this
.
find
(
'
input:checked
'
);
for
(
var
i
=
0
,
c
=
completedTodos
.
length
;
i
<
c
;
i
++
)
{
var
item
=
completedTodos
[
i
];
this
.
destroyTodo
(
$
(
item
));
}
},
destroyTodo
:
function
(
el
)
{
var
parent
=
el
.
parents
(
'
li
'
);
var
guid
=
parent
.
attr
(
'
data-todoid
'
);
delete
this
.
todos
[
guid
];
parent
.
remove
();
this
.
save
();
this
.
renderStats
();
}
});
//app
var
todos
=
new
TodoView
({
el
:
$
(
"
#todoapp
"
)
});
todo-example/fidel/images/destroy.png
0 → 100644
View file @
0b69fdca
555 Bytes
todo-example/fidel/index.html
0 → 100644
View file @
0b69fdca
<!DOCTYPE html>
<html>
<head>
<title>
Fidel
</title>
<link
href=
"stylesheets/todos.css"
media=
"all"
rel=
"stylesheet"
type=
"text/css"
/>
<!--<script src="vendor/live.js"></script>-->
</head>
<body>
<!-- Todo App Interface -->
<div
id=
"todoapp"
>
<div
class=
"title"
>
<h1>
Todos
</h1>
</div>
<div
class=
"content"
>
<div
id=
"create-todo"
>
<input
data-element=
"input"
placeholder=
"What needs to be done?"
type=
"text"
/>
<span
class=
"ui-tooltip-top"
style=
"display:none;"
>
Press Enter to save this task
</span>
</div>
<div
id=
"todos"
>
<ul
id=
"todo-list"
data-element=
"todosContainer"
></ul>
</div>
<div
id=
"todo-stats"
data-element=
"statsContainer"
></div>
</div>
</div>
<div
id=
"credits"
>
Created by
<br
/>
<a
href=
"http://jga.me/"
>
Greg Allen
</a>
(
<a
href=
"http://twitter.com/jgaui"
>
jgaui
</a>
).
</div>
<!-- Templates -->
<script
type=
"text/template"
id=
"item-template"
>
<
li
class
=
"
todo {!= todo.done ? 'done' : '' !}
"
data
-
todoid
=
"
{!= todo.guid !}
"
>
<
div
class
=
"
display
"
>
<
input
class
=
"
check
"
type
=
"
checkbox
"
{
!=
todo
.
done
?
'
checked="checked"
'
:
''
!
}
/
>
<
div
class
=
"
todo-content
"
>
{
!=
todo
.
name
!
}
<
/div
>
<
span
data
-
action
=
"
destroyTodo
"
class
=
"
todo-destroy
"
><
/span
>
<
/div
>
<
div
class
=
"
edit
"
>
<
input
class
=
"
todo-input
"
type
=
"
text
"
value
=
""
/>
<
/div
>
<
/li
>
</script>
<script
type=
"text/template"
id=
"stats-template"
>
{
!
if
(
total
)
{
!
}
<
span
class
=
"
todo-count
"
>
<
span
class
=
"
number
"
>
{
!=
remaining
!
}
<
/span
>
<
span
class
=
"
word
"
>
{
!=
remaining
==
1
?
'
item
'
:
'
items
'
!
}
<
/span> left
.
<
/span
>
{
!
}
!
}
{
!
if
(
done
)
{
!
}
<
span
class
=
"
todo-clear
"
>
<
a
data
-
action
=
"
clearCompleted
"
>
Clear
<
span
class
=
"
number-done
"
>
{
!=
done
!
}
<
/span
>
completed
<
span
class
=
"
word-done
"
>
{
!=
done
==
1
?
'
item
'
:
'
items
'
!
}
<
/span
>
<
/a
>
<
/span
>
{
!
}
!
}
</script>
<script
src=
"vendor/json2.js"
></script>
<script
src=
"vendor/jquery-1.6.4.min.js"
></script>
<script
src=
"vendor/fidel.js"
></script>
<!--<script src="../../lib/core.js"></script>-->
<!--<script src="../../lib/class.js"></script>-->
<!--<script src="../../lib/events.js"></script>-->
<!--<script src="../../lib/controller.js"></script>-->
<script
src=
"app.js"
></script>
</body>
</html>
todo-example/fidel/stylesheets/todos.css
0 → 100644
View file @
0b69fdca
This diff is collapsed.
Click to expand it.
todo-example/fidel/vendor/fidel.js
0 → 100644
View file @
0b69fdca
/*!
* Fidel - A javascript controller
* v1.2.2
* https://github.com/jgallen23/fidel
* copyright JGA 2011
* MIT License
*/
!
function
(
name
,
definition
)
{
if
(
typeof
module
!=
'
undefined
'
&&
module
.
exports
)
module
.
exports
=
definition
();
else
if
(
typeof
define
==
'
function
'
&&
typeof
define
.
amd
==
'
object
'
)
define
(
definition
);
else
this
[
name
]
=
definition
();
}(
'
Fidel
'
,
function
()
{
var
context
=
this
;
var
Fidel
=
{};
Fidel
.
guid
=
function
(){
return
'
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
'
.
replace
(
/
[
xy
]
/g
,
function
(
c
)
{
var
r
=
Math
.
random
()
*
16
|
0
,
v
=
c
===
'
x
'
?
r
:
(
r
&
0x3
|
0x8
);
return
v
.
toString
(
16
);
}).
toUpperCase
();
};
Fidel
.
extend
=
function
()
{
throw
new
Error
(
"
Fidel.extend is deprecated, please use Fidel.ViewController.extend
"
);
};
var
o
=
context
.
Fidel
;
Fidel
.
noConflict
=
function
()
{
context
.
Fidel
=
o
;
return
this
;
};
var
initializing
=
false
,
fnTest
=
/xyz/
.
test
(
function
(){
xyz
;})
?
/
\b
_super
\b
/
:
/.*/
;
// The base Class implementation (does nothing)
Fidel
.
Class
=
function
(){};
// Create a new Class that inherits from this class
Fidel
.
Class
.
extend
=
function
(
prop
)
{
var
_super
=
this
.
prototype
;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing
=
true
;
var
prototype
=
new
this
();
initializing
=
false
;
// Copy the properties over onto the new prototype
for
(
var
name
in
prop
)
{
// Check if we're overwriting an existing function
prototype
[
name
]
=
typeof
prop
[
name
]
==
"
function
"
&&
typeof
_super
[
name
]
==
"
function
"
&&
fnTest
.
test
(
prop
[
name
])
?
(
function
(
name
,
fn
){
return
function
()
{
var
tmp
=
this
.
_super
;
// Add a new ._super() method that is the same method
// but on the super-class
this
.
_super
=
_super
[
name
];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var
ret
=
fn
.
apply
(
this
,
arguments
);
this
.
_super
=
tmp
;
return
ret
;
};
})(
name
,
prop
[
name
])
:
prop
[
name
];
}
// The dummy class constructor
function
Class
(
opt
)
{
// All construction is actually done in the init method
if
(
!
initializing
)
{
if
(
this
.
defaults
)
{
for
(
var
key
in
this
.
defaults
)
{
if
(
typeof
opt
!==
'
object
'
||
!
opt
[
key
])
this
[
key
]
=
this
.
defaults
[
key
];
}
}
if
(
typeof
opt
===
'
object
'
)
{
for
(
var
okey
in
opt
)
{
this
[
okey
]
=
opt
[
okey
];
}
}
if
(
!
this
.
guid
)
this
.
guid
=
Fidel
.
guid
();
if
(
this
.
_initialize
)
this
.
_initialize
.
apply
(
this
,
arguments
);
if
(
this
.
init
)
this
.
init
.
apply
(
this
,
arguments
);
}
}
// Populate our constructed prototype object
Class
.
prototype
=
prototype
;
Class
.
prototype
.
proxy
=
function
(
func
)
{
var
thisObject
=
this
;
return
(
function
(){
if
(
!
func
)
return
;
return
func
.
apply
(
thisObject
,
arguments
);
});
};
// Enforce the constructor to be what we expect
Class
.
constructor
=
Class
;
// And make this class extendable
Class
.
extend
=
arguments
.
callee
;
return
Class
;
};
var
cache
=
{};
//check for "c_" cache for unit testing
//publish("/some/topic", ["a","b","c"]);
Fidel
.
publish
=
function
(
topic
,
args
){
var
subs
=
cache
[
topic
],
len
=
subs
?
subs
.
length
:
0
;
//can change loop or reverse array if the order matters
while
(
len
--
){
subs
[
len
].
apply
(
this
,
args
||
[]);
}
};
//subscribe("/some/topic", function(a, b, c){ /* handle data */ });
Fidel
.
subscribe
=
function
(
topic
,
callback
){
if
(
!
cache
[
topic
]){
cache
[
topic
]
=
[];
}
cache
[
topic
].
push
(
callback
);
return
[
topic
,
callback
];
// Array
};
//var handle = subscribe("/some/topic", function(){});
//unsubscribe(handle);
Fidel
.
unsubscribe
=
function
(
handle
){
var
subs
=
cache
[
handle
[
0
]],
callback
=
handle
[
1
],
len
=
subs
?
subs
.
length
:
0
;
while
(
len
--
){
if
(
subs
[
len
]
===
callback
){
subs
.
splice
(
len
,
1
);
}
}
};
Fidel
.
Class
.
prototype
.
on
=
Fidel
.
Class
.
prototype
.
bind
=
function
(
name
,
callback
)
{
return
Fidel
.
subscribe
(
this
.
guid
+
"
.
"
+
name
,
this
.
proxy
(
callback
));
};
Fidel
.
Class
.
prototype
.
emit
=
Fidel
.
Class
.
prototype
.
trigger
=
function
(
name
,
data
)
{
Fidel
.
publish
(
this
.
guid
+
"
.
"
+
name
,
data
);
Fidel
.
publish
(
name
,
data
);
};
Fidel
.
Class
.
prototype
.
removeListener
=
Fidel
.
Class
.
prototype
.
unbind
=
function
(
handle
)
{
Fidel
.
unsubscribe
(
handle
);
};
!
function
()
{
var
templateCache
=
{};
Fidel
.
template
=
function
tmpl
(
template
,
data
)
{
var
fn
=
!
/
\W
/
.
test
(
template
)
?
templateCache
[
template
]
=
templateCache
[
template
]
||
tmpl
(
template
)
:
new
Function
(
"
obj
"
,
"
var p=[],print=function(){p.push.apply(p,arguments);};
"
+
"
with(obj){p.push('
"
+
template
.
replace
(
/
[\r\t\n]
/g
,
""
)
.
split
(
"
{!
"
).
join
(
"
\t
"
)
.
replace
(
/
((
^|!}
)[^\t]
*
)
'/g
,
"
$1
\r
"
)
.
replace
(
/
\t
=
(
.*
?)
!}/g
,
"
',$1,'
"
)
.
split
(
"
\t
"
).
join
(
"
');
"
)
.
split
(
"
!}
"
).
join
(
"
p.push('
"
)
.
split
(
"
\r
"
).
join
(
"
\\
'
"
)
+
"
');}return p.join('');
"
);
return
data
?
fn
(
data
)
:
fn
;
};
}();
var
eventSplitter
=
/^
(\w
+
)\s
*
(
.*
)
$/
;
var
ViewController
=
Fidel
.
Class
.
extend
({
_initialize
:
function
(
options
)
{
if
(
!
this
.
el
)
throw
"
el is required
"
;
this
.
_subscribeHandles
=
{};
if
(
this
.
events
)
this
.
delegateEvents
();
if
(
this
.
elements
)
this
.
refreshElements
();
if
(
this
.
templates
)
this
.
loadTemplates
();
if
(
!
this
.
actionEvent
)
this
.
actionEvent
=
"
click
"
;
if
(
this
.
subscribe
)
this
.
bindSubscriptions
();
this
.
delegateActions
();
this
.
getDataElements
();
},
template
:
Fidel
.
template
,
delegateEvents
:
function
()
{
for
(
var
key
in
this
.
events
)
{
var
methodName
=
this
.
events
[
key
];
var
match
=
key
.
match
(
eventSplitter
);
var
eventName
=
match
[
1
],
selector
=
match
[
2
];
var
method
=
this
.
proxy
(
this
[
methodName
]);
if
(
selector
===
''
)
{
this
.
el
.
bind
(
eventName
,
method
);
}
else
{
this
.
el
.
delegate
(
selector
,
eventName
,
method
);
}
}
},
delegateActions
:
function
()
{
var
self
=
this
;
this
.
el
.
delegate
(
'
[data-action]
'
,
this
.
actionEvent
,
function
(
e
)
{
var
el
=
$
(
this
);
var
methodName
=
el
.
attr
(
'
data-action
'
);
if
(
self
[
methodName
])
self
[
methodName
].
call
(
self
,
el
,
e
);
});
},
refreshElements
:
function
()
{
for
(
var
key
in
this
.
elements
)
{
this
[
key
]
=
this
.
find
(
this
.
elements
[
key
]);
}
},
getDataElements
:
function
()
{
var
self
=
this
;
var
elements
=
this
.
find
(
"
[data-element]
"
);
for
(
var
i
=
0
,
c
=
elements
.
length
;
i
<
c
;
i
++
)
{
var
name
=
elements
[
i
].
getAttribute
(
'
data-element
'
);
if
(
!
self
[
name
])
{
var
elem
=
this
.
find
(
'
[data-element="
'
+
name
+
'
"]
'
);
self
[
name
]
=
elem
;
}
}
},
bindSubscriptions
:
function
()
{
for
(
var
key
in
this
.
subscribe
)
{
this
.
_subscribeHandles
[
key
]
=
Fidel
.
subscribe
(
key
,
this
.
proxy
(
this
[
this
.
subscribe
[
key
]]));
}
},
loadTemplates
:
function
()
{
for
(
var
name
in
this
.
templates
)
{
this
.
templates
[
name
]
=
$
(
this
.
templates
[
name
]).
html
();
}
},
find
:
function
(
selector
)
{
return
$
(
selector
,
this
.
el
[
0
]);
},
render
:
function
(
templateName
,
data
,
selector
)
{
if
(
arguments
.
length
==
1
)
{
data
=
templateName
;
templateName
=
this
.
primaryTemplate
;
}
template
=
this
.
templates
[
templateName
];
if
(
!
template
)
return
;
var
tmp
=
this
.
template
(
template
,
data
);
selector
=
(
selector
)?
$
(
selector
):
this
.
el
;
selector
.
html
(
tmp
);
},
destroy
:
function
()
{
for
(
var
key
in
this
.
_subscribeHandles
)
{
Fidel
.
unsubscribe
(
this
.
_subscribeHandles
[
key
]);
}
this
.
el
.
undelegate
(
'
[data-action]
'
,
this
.
actionEvent
);
this
.
el
=
null
;
}
});
Fidel
.
ViewController
=
ViewController
;
return
Fidel
;
});
todo-example/fidel/vendor/jquery-1.6.4.min.js
0 → 100644
View file @
0b69fdca
This diff is collapsed.
Click to expand it.
todo-example/fidel/vendor/json2.js
0 → 100644
View file @
0b69fdca
This diff is collapsed.
Click to expand it.
todo-example/fidel/vendor/live.js
0 → 100644
View file @
0b69fdca
/*
Live.js - One script closer to Designing in the Browser
Written for Handcraft.com by Martin Kool (@mrtnkl).
Version 4.
Recent change: Made stylesheet and mimetype checks case insensitive.
http://livejs.com
http://livejs.com/license (MIT)
@livejs
Include live.js#css to monitor css changes only.
Include live.js#js to monitor js changes only.
Include live.js#html to monitor html changes only.
Mix and match to monitor a preferred combination such as live.js#html,css
By default, just include live.js to monitor all css, js and html changes.
Live.js can also be loaded as a bookmarklet. It is best to only use it for CSS then,
as a page reload due to a change in html or css would not re-include the bookmarklet.
To monitor CSS and be notified that it has loaded, include it as: live.js#css,notify
*/
(
function
()
{
var
headers
=
{
"
Etag
"
:
1
,
"
Last-Modified
"
:
1
,
"
Content-Length
"
:
1
,
"
Content-Type
"
:
1
},
resources
=
{},
pendingRequests
=
{},
currentLinkElements
=
{},
oldLinkElements
=
{},
interval
=
1000
,
loaded
=
false
,
active
=
{
"
html
"
:
1
,
"
css
"
:
1
,
"
js
"
:
1
};
var
Live
=
{
// performs a cycle per interval
heartbeat
:
function
()
{
if
(
document
.
body
)
{
// make sure all resources are loaded on first activation
if
(
!
loaded
)
Live
.
loadresources
();
Live
.
checkForChanges
();
}
setTimeout
(
Live
.
heartbeat
,
interval
);
},
// loads all local css and js resources upon first activation
loadresources
:
function
()
{
// helper method to assert if a given url is local
function
isLocal
(
url
)
{
var
loc
=
document
.
location
,
reg
=
new
RegExp
(
"
^
\\
.|^
\
/(?!
\
/)|^[
\\
w]((?!://).)*$|
"
+
loc
.
protocol
+
"
//
"
+
loc
.
host
);
return
url
.
match
(
reg
);
}
// gather all resources
var
scripts
=
document
.
getElementsByTagName
(
"
script
"
),
links
=
document
.
getElementsByTagName
(
"
link
"
),
uris
=
[];
// track local js urls
for
(
var
i
=
0
;
i
<
scripts
.
length
;
i
++
)
{
var
script
=
scripts
[
i
],
src
=
script
.
getAttribute
(
"
src
"
);
if
(
src
&&
isLocal
(
src
))
uris
.
push
(
src
);
if
(
src
&&
src
.
match
(
/
\b
live.js#/
))
{
for
(
var
type
in
active
)
active
[
type
]
=
src
.
match
(
"
[#,|]
"
+
type
)
!=
null
if
(
src
.
match
(
"
notify
"
))
alert
(
"
Live.js is loaded.
"
);
}
}
if
(
!
active
.
js
)
uris
=
[];
if
(
active
.
html
)
uris
.
push
(
document
.
location
.
href
);
// track local css urls
for
(
var
i
=
0
;
i
<
links
.
length
&&
active
.
css
;
i
++
)
{
var
link
=
links
[
i
],
rel
=
link
.
getAttribute
(
"
rel
"
),
href
=
link
.
getAttribute
(
"
href
"
,
2
);
if
(
href
&&
rel
&&
rel
.
match
(
new
RegExp
(
"
stylesheet
"
,
"
i
"
))
&&
isLocal
(
href
))
{
uris
.
push
(
href
);
currentLinkElements
[
href
]
=
link
;
}
}
// initialize the resources info
for
(
var
i
=
0
;
i
<
uris
.
length
;
i
++
)
{
var
url
=
uris
[
i
];
Live
.
getHead
(
url
,
function
(
url
,
info
)
{
resources
[
url
]
=
info
;
});
}
// add rule for morphing between old and new css files
var
head
=
document
.
getElementsByTagName
(
"
head
"
)[
0
],
style
=
document
.
createElement
(
"
style
"
),
rule
=
"
transition: all .3s ease-out;
"
css
=
[
"
.livejs-loading * {
"
,
rule
,
"
-webkit-
"
,
rule
,
"
-moz-
"
,
rule
,
"
-o-
"
,
rule
,
"
}
"
].
join
(
''
);
style
.
setAttribute
(
"
type
"
,
"
text/css
"
);
head
.
appendChild
(
style
);
style
.
styleSheet
?
style
.
styleSheet
.
cssText
=
css
:
style
.
appendChild
(
document
.
createTextNode
(
css
));
// yep
loaded
=
true
;
},
// check all tracking resources for changes
checkForChanges
:
function
()
{
for
(
var
url
in
resources
)
{
if
(
pendingRequests
[
url
])
continue
;
Live
.
getHead
(
url
,
function
(
url
,
newInfo
)
{
var
oldInfo
=
resources
[
url
],
hasChanged
=
false
;
resources
[
url
]
=
newInfo
;
for
(
var
header
in
oldInfo
)
{
// do verification based on the header type
var
oldValue
=
oldInfo
[
header
],
newValue
=
newInfo
[
header
],
contentType
=
newInfo
[
"
Content-Type
"
];
switch
(
header
.
toLowerCase
())
{
case
"
etag
"
:
if
(
!
newValue
)
break
;
// fall through to default
default
:
hasChanged
=
oldValue
!=
newValue
;
break
;
}
// if changed, act
if
(
hasChanged
)
{
Live
.
refreshResource
(
url
,
contentType
);
break
;
}
}
});
}
},
// act upon a changed url of certain content type
refreshResource
:
function
(
url
,
type
)
{
switch
(
type
.
toLowerCase
())
{
// css files can be reloaded dynamically by replacing the link element
case
"
text/css
"
:
var
link
=
currentLinkElements
[
url
],
html
=
document
.
body
.
parentNode
,
head
=
link
.
parentNode
,
next
=
link
.
nextSibling
,
newLink
=
document
.
createElement
(
"
link
"
);
html
.
className
=
html
.
className
.
replace
(
/
\s
*livejs
\-
loading/gi
,
''
)
+
'
livejs-loading
'
;
newLink
.
setAttribute
(
"
type
"
,
"
text/css
"
);
newLink
.
setAttribute
(
"
rel
"
,
"
stylesheet
"
);
newLink
.
setAttribute
(
"
href
"
,
url
+
"
?now=
"
+
new
Date
()
*
1
);
next
?
head
.
insertBefore
(
newLink
,
next
)
:
head
.
appendChild
(
newLink
);
currentLinkElements
[
url
]
=
newLink
;
oldLinkElements
[
url
]
=
link
;
// schedule removal of the old link
Live
.
removeoldLinkElements
();
break
;
// check if an html resource is our current url, then reload
case
"
text/html
"
:
if
(
url
!=
document
.
location
.
href
)
return
;
// local javascript changes cause a reload as well
case
"
text/javascript
"
:
case
"
application/javascript
"
:
case
"
application/x-javascript
"
:
document
.
location
.
reload
();
}
},
// removes the old stylesheet rules only once the new one has finished loading
removeoldLinkElements
:
function
()
{
var
pending
=
0
;
for
(
var
url
in
oldLinkElements
)
{
// if this sheet has any cssRules, delete the old link
try
{
var
link
=
currentLinkElements
[
url
],
oldLink
=
oldLinkElements
[
url
],
html
=
document
.
body
.
parentNode
,
sheet
=
link
.
sheet
||
link
.
styleSheet
,
rules
=
sheet
.
rules
||
sheet
.
cssRules
;
if
(
rules
.
length
>=
0
)
{
oldLink
.
parentNode
.
removeChild
(
oldLink
);
delete
oldLinkElements
[
url
];
setTimeout
(
function
()
{
html
.
className
=
html
.
className
.
replace
(
/
\s
*livejs
\-
loading/gi
,
''
);
},
100
);
}
}
catch
(
e
)
{
pending
++
;
}
if
(
pending
)
setTimeout
(
Live
.
removeoldLinkElements
,
50
);
}
},
// performs a HEAD request and passes the header info to the given callback
getHead
:
function
(
url
,
callback
)
{
pendingRequests
[
url
]
=
true
;
var
xhr
=
window
.
XMLHttpRequest
?
new
XMLHttpRequest
()
:
new
ActiveXObject
(
"
Microsoft.XmlHttp
"
);
xhr
.
open
(
"
HEAD
"
,
url
,
true
);
xhr
.
onreadystatechange
=
function
()
{
delete
pendingRequests
[
url
];
if
(
xhr
.
readyState
==
4
&&
xhr
.
status
!=
304
)
{
xhr
.
getAllResponseHeaders
();
var
info
=
{};
for
(
var
h
in
headers
)
{
var
value
=
xhr
.
getResponseHeader
(
h
);
// adjust the simple Etag variant to match on its significant part
if
(
h
.
toLowerCase
()
==
"
etag
"
&&
value
)
value
=
value
.
replace
(
/^W
\/
/
,
''
);
if
(
h
.
toLowerCase
()
==
"
content-type
"
&&
value
)
value
=
value
.
replace
(
/^
(
.*
?)
;.*
?
$/i
,
"
$1
"
);
info
[
h
]
=
value
;
}
callback
(
url
,
info
);
}
}
xhr
.
send
();
}
};
// start listening
if
(
document
.
location
.
protocol
!=
"
file:
"
)
{
if
(
!
window
.
liveJsLoaded
)
Live
.
heartbeat
();
window
.
liveJsLoaded
=
true
;
}
else
if
(
window
.
console
)
console
.
log
(
"
Live.js doesn't support the file protocol. It needs http.
"
);
})();
\ No newline at end of file
todo-example/fidel/vendor/todos.js
0 → 100644
View file @
0b69fdca
// An example Backbone application contributed by
// [Jérôme Gravel-Niquet](http://jgn.me/). This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.
// Load the application once the DOM is ready, using `jQuery.ready`:
$
(
function
(){
// Todo Model
// ----------
// Our basic **Todo** model has `content`, `order`, and `done` attributes.
window
.
Todo
=
Backbone
.
Model
.
extend
({
// Default attributes for the todo.
defaults
:
{
content
:
"
empty todo...
"
,
done
:
false
},
// Ensure that each todo created has `content`.
initialize
:
function
()
{
if
(
!
this
.
get
(
"
content
"
))
{
this
.
set
({
"
content
"
:
this
.
defaults
.
content
});
}
},
// Toggle the `done` state of this todo item.
toggle
:
function
()
{
this
.
save
({
done
:
!
this
.
get
(
"
done
"
)});
},
// Remove this Todo from *localStorage* and delete its view.
clear
:
function
()
{
this
.
destroy
();
this
.
view
.
remove
();
}
});
// Todo Collection
// ---------------
// The collection of todos is backed by *localStorage* instead of a remote
// server.
window
.
TodoList
=
Backbone
.
Collection
.
extend
({
// Reference to this collection's model.
model
:
Todo
,
// Save all of the todo items under the `"todos"` namespace.
localStorage
:
new
Store
(
"
todos
"
),
// Filter down the list of all todo items that are finished.
done
:
function
()
{
return
this
.
filter
(
function
(
todo
){
return
todo
.
get
(
'
done
'
);
});
},
// Filter down the list to only todo items that are still not finished.
remaining
:
function
()
{
return
this
.
without
.
apply
(
this
,
this
.
done
());
},
// We keep the Todos in sequential order, despite being saved by unordered
// GUID in the database. This generates the next order number for new items.
nextOrder
:
function
()
{
if
(
!
this
.
length
)
return
1
;
return
this
.
last
().
get
(
'
order
'
)
+
1
;
},
// Todos are sorted by their original insertion order.
comparator
:
function
(
todo
)
{
return
todo
.
get
(
'
order
'
);
}
});
// Create our global collection of **Todos**.
window
.
Todos
=
new
TodoList
;
// Todo Item View
// --------------
// The DOM element for a todo item...
window
.
TodoView
=
Backbone
.
View
.
extend
({
//... is a list tag.
tagName
:
"
li
"
,
// Cache the template function for a single item.
template
:
_
.
template
(
$
(
'
#item-template
'
).
html
()),
// The DOM events specific to an item.
events
:
{
"
click .check
"
:
"
toggleDone
"
,
"
dblclick div.todo-content
"
:
"
edit
"
,
"
click span.todo-destroy
"
:
"
clear
"
,
"
keypress .todo-input
"
:
"
updateOnEnter
"
},
// The TodoView listens for changes to its model, re-rendering. Since there's
// a one-to-one correspondence between a **Todo** and a **TodoView** in this
// app, we set a direct reference on the model for convenience.
initialize
:
function
()
{
_
.
bindAll
(
this
,
'
render
'
,
'
close
'
);
this
.
model
.
bind
(
'
change
'
,
this
.
render
);
this
.
model
.
view
=
this
;
},
// Re-render the contents of the todo item.
render
:
function
()
{
$
(
this
.
el
).
html
(
this
.
template
(
this
.
model
.
toJSON
()));
this
.
setContent
();
return
this
;
},
// To avoid XSS (not that it would be harmful in this particular app),
// we use `jQuery.text` to set the contents of the todo item.
setContent
:
function
()
{
var
content
=
this
.
model
.
get
(
'
content
'
);
this
.
$
(
'
.todo-content
'
).
text
(
content
);
this
.
input
=
this
.
$
(
'
.todo-input
'
);
this
.
input
.
bind
(
'
blur
'
,
this
.
close
);
this
.
input
.
val
(
content
);
},
// Toggle the `"done"` state of the model.
toggleDone
:
function
()
{
this
.
model
.
toggle
();
},
// Switch this view into `"editing"` mode, displaying the input field.
edit
:
function
()
{
$
(
this
.
el
).
addClass
(
"
editing
"
);
this
.
input
.
focus
();
},
// Close the `"editing"` mode, saving changes to the todo.
close
:
function
()
{
this
.
model
.
save
({
content
:
this
.
input
.
val
()});
$
(
this
.
el
).
removeClass
(
"
editing
"
);
},
// If you hit `enter`, we're through editing the item.
updateOnEnter
:
function
(
e
)
{
if
(
e
.
keyCode
==
13
)
this
.
close
();
},
// Remove this view from the DOM.
remove
:
function
()
{
$
(
this
.
el
).
remove
();
},
// Remove the item, destroy the model.
clear
:
function
()
{
this
.
model
.
clear
();
}
});
// The Application
// ---------------
// Our overall **AppView** is the top-level piece of UI.
window
.
AppView
=
Backbone
.
View
.
extend
({
// Instead of generating a new element, bind to the existing skeleton of
// the App already present in the HTML.
el
:
$
(
"
#todoapp
"
),
// Our template for the line of statistics at the bottom of the app.
statsTemplate
:
_
.
template
(
$
(
'
#stats-template
'
).
html
()),
// Delegated events for creating new items, and clearing completed ones.
events
:
{
"
keypress #new-todo
"
:
"
createOnEnter
"
,
"
keyup #new-todo
"
:
"
showTooltip
"
,
"
click .todo-clear a
"
:
"
clearCompleted
"
},
// At initialization we bind to the relevant events on the `Todos`
// collection, when items are added or changed. Kick things off by
// loading any preexisting todos that might be saved in *localStorage*.
initialize
:
function
()
{
_
.
bindAll
(
this
,
'
addOne
'
,
'
addAll
'
,
'
render
'
);
this
.
input
=
this
.
$
(
"
#new-todo
"
);
Todos
.
bind
(
'
add
'
,
this
.
addOne
);
Todos
.
bind
(
'
reset
'
,
this
.
addAll
);
Todos
.
bind
(
'
all
'
,
this
.
render
);
Todos
.
fetch
();
},
// Re-rendering the App just means refreshing the statistics -- the rest
// of the app doesn't change.
render
:
function
()
{
var
done
=
Todos
.
done
().
length
;
this
.
$
(
'
#todo-stats
'
).
html
(
this
.
statsTemplate
({
total
:
Todos
.
length
,
done
:
Todos
.
done
().
length
,
remaining
:
Todos
.
remaining
().
length
}));
},
// Add a single todo item to the list by creating a view for it, and
// appending its element to the `<ul>`.
addOne
:
function
(
todo
)
{
var
view
=
new
TodoView
({
model
:
todo
});
this
.
$
(
"
#todo-list
"
).
append
(
view
.
render
().
el
);
},
// Add all items in the **Todos** collection at once.
addAll
:
function
()
{
Todos
.
each
(
this
.
addOne
);
},
// Generate the attributes for a new Todo item.
newAttributes
:
function
()
{
return
{
content
:
this
.
input
.
val
(),
order
:
Todos
.
nextOrder
(),
done
:
false
};
},
// If you hit return in the main input field, create new **Todo** model,
// persisting it to *localStorage*.
createOnEnter
:
function
(
e
)
{
if
(
e
.
keyCode
!=
13
)
return
;
Todos
.
create
(
this
.
newAttributes
());
this
.
input
.
val
(
''
);
},
// Clear all done todo items, destroying their models.
clearCompleted
:
function
()
{
_
.
each
(
Todos
.
done
(),
function
(
todo
){
todo
.
clear
();
});
return
false
;
},
// Lazily show the tooltip that tells you to press `enter` to save
// a new todo item, after one second.
showTooltip
:
function
(
e
)
{
var
tooltip
=
this
.
$
(
"
.ui-tooltip-top
"
);
var
val
=
this
.
input
.
val
();
tooltip
.
fadeOut
();
if
(
this
.
tooltipTimeout
)
clearTimeout
(
this
.
tooltipTimeout
);
if
(
val
==
''
||
val
==
this
.
input
.
attr
(
'
placeholder
'
))
return
;
var
show
=
function
(){
tooltip
.
show
().
fadeIn
();
};
this
.
tooltipTimeout
=
_
.
delay
(
show
,
1000
);
}
});
// Finally, we kick things off by creating the **App**.
window
.
App
=
new
AppView
;
});
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