Conflicts:
	.gitignore
This commit is contained in:
Rob Spies 2010-06-22 17:09:55 -07:00
commit 1500e91def
140 changed files with 24534 additions and 1 deletions

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;launchConfigurationWorkingSet editPageId=&quot;org.eclipse.ui.resourceWorkingSetPage&quot; factoryID=&quot;org.eclipse.ui.internal.WorkingSetFactory&quot; id=&quot;1262905463390_2&quot; label=&quot;workingSet&quot; name=&quot;workingSet&quot;&gt;&#10;&lt;item factoryID=&quot;org.eclipse.ui.internal.model.ResourceFactory&quot; path=&quot;/angular.js/test&quot; type=&quot;2&quot;/&gt;&#10;&lt;item factoryID=&quot;org.eclipse.ui.internal.model.ResourceFactory&quot; path=&quot;/angular.js/src&quot; type=&quot;2&quot;/&gt;&#10;&lt;/launchConfigurationWorkingSet&gt;}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js}/test.sh"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
</launchConfiguration>

11
.gitignore vendored
View file

@ -1,3 +1,4 @@
<<<<<<< HEAD
.git4_perforce_config
blaze-eclipse
google3/blaze-*
@ -21,4 +22,12 @@ google3/.gwt-tmp
google3/alloc
google3tomcat
google3/mbin
google3/mgenfiles
google3/mgenfiles
=======
angular-minified.map
externs.js
angular.js
angular-minified.js
angular-debug.js
angular-scenario.js
>>>>>>> b129a1094e6b42ed82c3ccecc2f40daaa0a6cb6a

1
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
workspace.xml

7
.idea/.rakeTasks Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Settings><!--This file was automatically generated by Ruby plugin.
You are allowed to:
1. Remove rake task
2. Add existing rake tasks
To add existing rake tasks automatically delete this file and reload the project.
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Compile JavaScript" fullCmd="compile" taksId="compile" /><RakeTask description="Generate Externs" fullCmd="compileexterns" taksId="compileexterns" /><RakeTask description="Lint" fullCmd="lint" taksId="lint" /><RakeGroup description="" fullCmd="" taksId="server"><RakeTask description="Run JsTestDriver Server" fullCmd="server:start" taksId="start" /><RakeTask description="Run JavaScript tests against the server" fullCmd="server:test" taksId="test" /></RakeGroup><RakeTask description="Run JavaScript tests" fullCmd="test" taksId="test" /><RakeTask description="" fullCmd="default" taksId="default" /></RakeGroup></Settings>

5
.idea/encodings.xml Normal file
View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>

9
.idea/master.iml Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RUBY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

14
.idea/misc.xml Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DependencyValidationManager">
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</component>
<component name="ProjectDetails">
<option name="projectName" value="master" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Ruby SDK 1.8.7 (/usr/bin/ruby)" project-jdk-type="RUBY_SDK" />
<component name="SvnBranchConfigurationManager">
<option name="mySupportsUserInfoFilter" value="true" />
</component>
</project>

9
.idea/modules.xml Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/master.iml" filepath="$PROJECT_DIR$/.idea/master.iml" />
</modules>
</component>
</project>

8
.idea/vcs.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

27
.project Normal file
View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>angular.js</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>auto,full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/JSTD_Tests.launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>

9
.settings/.jsdtscope Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry excluding="test/" kind="src" path="src"/>
<classpathentry kind="src" path="src/test"/>
<classpathentry excluding="test/" kind="src" path="test"/>
<classpathentry kind="src" path="test/test"/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
</classpath>

View file

@ -0,0 +1 @@
org.eclipse.wst.jsdt.launching.JRE_CONTAINER

View file

@ -0,0 +1 @@
Global

22
LICENSE Normal file
View file

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

12
README.md Normal file
View file

@ -0,0 +1,12 @@
Angular
======
Compiling
---------
rake compile
Running Tests
-------------
rake server:start
rake test

119
Rakefile Normal file
View file

@ -0,0 +1,119 @@
include FileUtils
task :default => [:compile, :test]
desc 'Generate Externs'
task :compile_externs do
out = File.new("externs.js", "w")
out.write("function _(){};\n")
file = File.new("lib/underscore/underscore.js", "r")
while (line = file.gets)
if line =~ /^\s*_\.(\w+)\s*=.*$/
out.write("_.#{$1}=function(){};\n")
end
end
file.close
out.write("function jQuery(){};\n")
file = File.new("lib/jquery/jquery-1.4.2.js", "r")
while (line = file.gets)
if line =~ /^\s*(\w+)\s*:\s*function.*$/
out.write("jQuery.#{$1}=function(){};\n")
end
end
file.close
out.write("jQuery.scope=function(){};\n")
out.write("jQuery.controller=function(){};\n")
out.close
end
desc 'Compile Scenario'
task :compile_scenario do
concat = %x(cat \
lib/underscore/underscore.js \
lib/jquery/jquery-1.4.2.js \
src/scenario/angular.prefix \
src/Angular.js \
src/JSON.js \
src/Scope.js \
src/Parser.js \
src/Resource.js \
src/Browser.js \
src/apis.js \
src/services.js \
src/AngularPublic.js \
src/scenario/Runner.js \
src/scenario/DSL.js \
src/scenario/angular.suffix \
)
css = %x(cat css/angular-scenario.css)
f = File.new("angular-scenario.js", 'w')
f.write(concat)
f.write('document.write(\'<style type="text/css">\n')
f.write(css.gsub(/'/, "\\'").gsub(/\n/, "\\n"));
f.write('\n</style>\');')
f.close
end
desc 'Compile JavaScript'
task :compile do
Rake::Task['compile_externs'].execute 0
Rake::Task['compile_scenario'].execute 0
concat = %x(cat \
src/angular.prefix \
src/Angular.js \
src/JSON.js \
src/Compiler.js \
src/Scope.js \
src/Parser.js \
src/Resource.js \
src/Browser.js \
src/jqLite.js \
src/apis.js \
src/filters.js \
src/formatters.js \
src/validators.js \
src/services.js \
src/directives.js \
src/markups.js \
src/widgets.js \
src/AngularPublic.js \
src/angular.suffix \
)
f = File.new("angular-debug.js", 'w')
f.write(concat)
f.close
%x(java -jar lib/compiler-closure/compiler.jar \
--compilation_level ADVANCED_OPTIMIZATIONS \
--js angular-debug.js \
--externs externs.js \
--create_source_map ./angular-minified.map \
--js_output_file angular-minified.js)
end
namespace :server do
desc 'Run JsTestDriver Server'
task :start do
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
end
desc "Run JavaScript tests against the server"
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all)
end
end
desc "Run JavaScript tests"
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876)
end
desc 'Lint'
task :lint do
out = %x(lib/jsl/jsl -conf lib/jsl/jsl.default.conf)
print out
end

6
TODO.text Normal file
View file

@ -0,0 +1,6 @@
* move angular-bootstrap.js out of anugular.js.
* 'angular' is the official namespace for public API
- angular.defaults = {}
- var scope = angular.compile(element, options);
* angular.js is not self boot straping by default.
* Remove SWFObject

76
css/angular-scenario.css Normal file
View file

@ -0,0 +1,76 @@
@charset "UTF-8";
/* CSS Document */
#runner {
position: absolute;
top:5px;
left:10px;
right:10px;
height: 200px;
}
.console {
display: block;
overflow: scroll;
height: 200px;
border: 1px solid black;
}
#testView {
position: absolute;
bottom:10px;
top:230px;
left:10px;
right:10px;
}
#testView iframe {
width: 100%;
height: 100%;
}
li.running > span {
background-color: yellow;
}
#runner span {
background-color: green;
}
#runner .fail > span {
background-color: red;
}
.collapsed > ul {
display: none;
}
//////
.run, .info, .error {
display: block;
padding: 0 1em;
font-family: monospace;
white-space: pre;
}
.run {
background-color: lightgrey;
padding: 0 .2em;
}
.run.pass {
background-color: lightgreen;
}
.run.fail {
background-color: lightred;
}
.name, .time, .state {
padding-right: 2em;
}
error {
color: red;
}

189
css/angular.css Normal file
View file

@ -0,0 +1,189 @@
@charset "UTF-8";
/* CSS Document */
#ng-console {
border: thin solid black;
font-family: 'courier';
font-size: x-small;
}
#ng-console .ng-console-error {
color: red;
}
#ng-console .ng-console-info {
color: blue;
}
.ng-upload-widget object {
align:center;
}
.ng-upload-widget a {
margin-right: .3em;
}
.ng-upload-widget span {
color: #999999;
font-size: smaller;
}
.ng-format-negative {
color: red;
}
.ng-exception {
border: 2px solid #FF0000;
font-family: "Courier New", Courier, monospace;
font-size: smaller;
}
.ng-validation-error {
border: 2px solid #FF0000;
}
.ng-hidden {
display:none;
}
/*****************
* DatePicker
*****************/
div.ui-widget {
font-size: 11px;
}
/*****************
* OrderBy
*****************/
.ng-ascend,
.ng-descend {
padding-right: 20px;
background-repeat: no-repeat;
background-position: right;
}
.ng-ascend { background-image: url(angular_images/arrow_ascend.png); }
.ng-descend { background-image: url(angular_images/arrow_descend.png); }
/*****************
* TIP
*****************/
#ng-callout {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 13px;
font-weight: normal;
font-family: Verdana, Arial, Helvetica, sans-serif;
vertical-align: baseline;
background: transparent;
text-decoration: none;
}
#ng-callout .ng-arrow-left{
background-image: url(angular_images/arrow_left.gif);
background-repeat: no-repeat;
background-position: left top;
position: absolute;
z-index:101;
left:-12px;
height:23px;
width:10px;
top:-3px;
}
#ng-callout .ng-arrow-right{
background-image: url(angular_images/arrow_right.gif);
background-repeat: no-repeat;
background-position: left top;
position: absolute;
z-index:101;
height:23px;
width:11px;
top:-2px;
}
#ng-callout {
position: absolute;
z-index:100;
border: 2px solid #CCCCCC;
background-color: #fff;
}
#ng-callout .ng-content{
padding:10px 10px 10px 10px;
color:#333333;
}
#ng-callout .ng-title{
background-color: #CCCCCC;
text-align: left;
padding-left: 8px;
padding-bottom: 5px;
padding-top: 2px;
font-weight:bold;
}
#ng-spacer {
height: 1.2em;
}
#ng-loading {
position: fixed;
bottom: 0;
height: 1.2em;
width: 100%;
text-align: center;
}
/*****************
* Login
*****************/
#ng-login {
z-index: 2000;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding-top: 100px;
}
#ng-login .ng-login-container {
width: 500px;
height: 380px;
margin: auto;
border-top: 5px solid #FFF;
border-left: 5px solid #DDD;
border-right: 5px solid #777;
border-bottom: 5px solid #555;
padding: 0 3px 3px 0;
}
#ng-login .ng-login-container iframe {
width: 100%;
height: 100%;
border: 2px solid black;
}
/*****************
* indicators
*****************/
.ng-indicator-wait {
display: inline-block;
height: 16px;
width: 16px;
background-image: url("angular_images/indicator-wait.png");
}
.ng-input-indicator-wait {
background-image: url("angular_images/indicator-wait.png");
background-position: right;
background-repeat: no-repeat;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../lib/underscore/underscore.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery-1.3.2.js"></script>
<script type="text/javascript" src="../src/angular-bootstrap.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var scope = angular.compile(document);
scope.set('a', 3);
scope.updateView();
});
</script>
</head>
<body>
Quantity: <input type="text" name="a" value="2">
*
Cost: <input type="text" name="b" value="3.4">
= {{a * b | currency}}
</body>
</html>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../lib/underscore/underscore.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery-1.3.2.js"></script>
<script type="text/javascript" src="../angular-minified.js"></script>
<script type="text/javascript">
$(document).ready(function(){
scope = angular.compile(document);
scope.set('a', 3);
scope.updateView();
});
</script>
</head>
<body>
Quantity: <input type="text" name="a" value="2">
*
Cost: <input type="text" name="b" value="3.4">
= {{a * b | currency}}
</body>
</html>

21
example/calculator.html Normal file
View file

@ -0,0 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../lib/underscore/underscore.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery-1.3.2.js"></script>
<script type="text/javascript" src="../angular.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var scope = angular.compile(document);
scope.set('a', 3);
scope.updateView();
});
</script>
</head>
<body>
Quantity: <input type="text" name="a" value="2">
*
Cost: <input type="text" name="b" value="3.4">
= {{a * b | currency}}
</body>
</html>

11
example/index.html Normal file
View file

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
</head>
<body>
<ul>
<li><a href="calculator-bootstrap.html">Calculator: Auto Init</a></li>
<li><a href="calculator.html">Calculator: Manual Init</a></li>
</ul>
</body>
</html>

55
example/memoryLeak.html Normal file
View file

@ -0,0 +1,55 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../lib/underscore/underscore.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery-1.3.2.js"></script>
<script type="text/javascript" src="../src/angular-bootstrap.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var scope = angular.compile(document);
scope.init();
scope.set("add", function(){
var partial = $("#partial");
//id++;
partial.html('<div>{{ error() }}<br/></div>');
var scope = angular.compile(partial);
scope.set("hello", function (){
return 'who dat?';
});
scope.set("error", function (){
this.misko.length;
});
function XXXXXXXXX(){};
scope.set('xxx', new XXXXXXXXX());
scope.set("names", ["adam", "misko", "shyam"]);
scope.init();
});
scope.set("remove", function(){
var partial = $("#partial");
/*
partial.find('*').andSelf().each(function(){
var scope = $(this).data('scope');
if (scope) {
delete scope.state;
delete scope.widgets;
}
var cntl = $(this).data('controller');
if (cntl) {
delete cntl.view;
}
$(this).removeData();
});
*/
partial.removeData('scope');
partial.children().remove();
});
});
</script>
<link rel="StyleSheet" type="text/css" href="../css/angular.css"/>
</head>
<body>
<input type="button" value="add" ng-click="add()"/>
<input type="button" value="remove" ng-click="remove()"/>
<div id="partial"></div>
</body>
</html>

13
example/temp.html Normal file
View file

@ -0,0 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../src/angular-bootstrap.js#autobind"></script>
</head>
<body>
{{$location.hashSearch.order}} <br/>
<input type="radio" name="$location.hashSearch.order" value="A"/> A <br/>
<input type="radio" name="$location.hashSearch.order" checked value="B"/> B <br/>
<input type="radio" name="$location.hashSearch.order" value="C"/> C <br/>
{{$location.hashSearch.order}} <br/>
</body>
</html>

98
example/tweeter/style.css Normal file
View file

@ -0,0 +1,98 @@
.loading {display: none;}
.fetching .loading {display: block;}
a {
color: blue;
}
h1 {
background-color: black;
margin: 0;
padding: .25em;
color: white;
border-bottom: 5px solid gray;
}
.box {
border: 2px solid gray;
}
.tweeter {
margin-right: 360px;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
margin: .25em;
padding: 2px;
}
li img {
float: left;
margin: 2px;
margin-right: .5em;
max-height: 48px;
min-height: 48px;
}
li.even {
background-color: lightgray;
}
.addressbook {
float: right;
width: 350px;
}
.addressbook li {
font-size: .9em;
}
.clrleft {
clear: left;
}
.notes {
font-size: .8em;
color: gray;
}
.username, .nickname {
font-weight: bold;
}
.editor {
padding: 4px;
}
label {
color: gray;
display: inline-block;
width: 75px;
text-align: right;
padding: 2px;
margin-top: 10px;
}
.editor input[type=text],
.editor textarea {
width: 230px;
vertical-align: text-top;
}
.editor TEXTAREA {
height: 50px;
}
.debug{
font-size: .7em;
white-space: pre;
padding: 0;
margin: 0;
}

View file

@ -0,0 +1,80 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="../../css/angular.css">
<script type="text/javascript" src="../../lib/underscore/underscore.js"></script>
<script type="text/javascript" src="../../lib/jquery/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="../../src/angular-bootstrap.js"></script>
<script type="text/javascript" src="tweeterclient.js"></script>
</head>
<body ng-class="status" ng-init="mute={}" ng-watch="$anchor.user: tweets = fetchTweets($anchor.user)">
<div class="addressbook box">
<h1>Address Book</h1>
[ Filter: <input type="text" name="userFilter"/>]
<ul>
<li ng-repeat="user in users.$filter(userFilter).$orderBy('screen_name')" ng-class-even="'even'" ng-class-odd="'odd'">
<a href="" ng-click="$anchor.user=user.screen_name"><img src="{{user.profile_image_url}}"/></a>
<a href="" ng-click="$anchor.user=user.screen_name">{{user.screen_name}}</a>
as <span class="nickname">{{user.name}}</span>
[ <a href="#" ng-click="$anchor.edituser=user.screen_name">edit</a>
| <a href="#" ng-click="users.$remove(user)">X</a>
| <a href="#" ng-click="mute[user.screen_name] = ! mute[user.screen_name]">mute</a>
]
<div class="notes">{{user.notes|linky}}</div>
<div class="clrleft"></div>
</li>
</ul>
<hr/>
<div ng-show="$anchor.edituser" ng-eval="user = users.$find({:$.screen_name == $anchor.edituser})">
<div class="editor">
<label>Username:</label>
<input type="text" name="user.screen_name" disabled="disabled"/>
<label>Name:</label>
<input type="text" name="user.name"/>
<label>Image:</label>
<input type="text" name="user.profile_image_url"/>
<label>Notes:</label>
<textarea type="text" name="user.notes"></textarea>
<input type="button" ng-click="$anchor.edituser=undefined" value="Close"/>
</div>
</div>
<hr/>
<div class="debug">
mute={{mute|json}}
userFilter={{userFilter|json}}
tweetFilter={{tweetFilter|json}}
$anchor={{$anchor}}
users={{users}}
tweets={{tweets}}
</div>
</div>
<div class="tweeter box">
<h1>Tweets: {{$anchor.user}}</h1>
[ Filter: <input type="text" name="tweetFilter"/>
<span ng-show="$anchor.user">| <a href="#user=">&lt;&lt; All</a></span>
]
<div class="loading">Loading...</div>
<ul>
<li ng-repeat="tweet in tweets.$filter(tweetFilter).$filter({:!mute[$.user.screen_name]})"
ng-class-even="'even'" ng-class-odd="'odd'"
ng-eval="user = users.$find({: $.screen_name == tweet.user.screen_name}) || tweet.user">
<img src="{{user.profile_image_url}}"/>
[ <a href="" ng-click="$anchor.user=user.screen_name">{{user.nickname || user.name || user.screen_name }}</a>
| <a href="" ng-click="users.$includeIf(user, true)">+</a>
]:
{{tweet.text | linky}}
<span class="notes">{{tweet.created_at}}</span>
<span class="notes">{{user.notes}}</span>
<div class="clrleft"></div>
</li>
</ul>
</div>
</body>
</html>

View file

@ -0,0 +1,34 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="../../css/angular.css">
<script type="text/javascript" src="../../lib/underscore/underscore.js"></script>
<script type="text/javascript" src="../../lib/jquery/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="../../src/angular-bootstrap.js"></script>
<script type="text/javascript" src="tweeterclient.js"></script>
</head>
<body ng-class="status" Xng-init="tweets = fetchTweets()">
(TODO: I should fetch current tweets)
<div class="tweeter box">
<h1>Tweets: {{$anchor.user}}</h1>
[ Filter: <input type="text" name="tweetFilter"/> (TODO: this should act as search box)
<span ng-show="$anchor.user">| <a href="#user=">&lt;&lt; All</a></span>
]
<div class="loading">Loading...</div>
<ul>
<li Xng-repeat="tweet in tweets"
ng-class-even="'even'" ng-class-odd="'odd'">
<img src="{{tweet.user.profile_image_url}}"/>
[ <a href="" Xng-click="$anchor.user=tweet.user.screen_name">{{tweet.user.nickname || tweet.user.name || tweet.user.screen_name }}</a>
]:
{{tweet.text}} (TODO: I want urls as links)
<span class="notes">{{tweet.created_at}}</span>
<span class="notes">{{tweet.user.notes}}</span>
<div class="clrleft"></div>
</li>
</ul>
</div>
<pre>tweets=(TODO: display me!!!)</pre>
</body>
</html>

View file

@ -0,0 +1,36 @@
function noop(){}
$(document).ready(function(){
function xhr(method, url, data, callback){
jQuery.getJSON(url, function(){
callback.apply(this, arguments);
scope.updateView();
});
}
var resourceFactory = new ResourceFactory(xhr);
var Tweeter = resourceFactory.route("http://twitter.com/statuses/:service:username.json", {}, {
home: {method:'GET', params: {service:'home_timeline'}, isArray:true },
user: {method:'GET', params: {service:'user_timeline/'}, isArray:true }
});
var scope = window.scope = angular.compile(document, {
location:angular.startUrlWatcher()
});
function fetchTweets(username){
return username ? Tweeter.user({username: username}) : Tweeter.home();
}
scope.set('fetchTweets', fetchTweets);
scope.set('users', [
{screen_name:'mhevery', name:'Mi\u0161ko Hevery',
notes:'Author of <angular/> http://www.getangular.com.',
profile_image_url:'http://a3.twimg.com/profile_images/54360179/Me_-_Small_Banner_normal.jpg'},
{screen_name:'abrons', name:'Adam Abrons',
notes:'Author of <angular/> & Ruby guru see: http://www.angularjs.org.',
profile_image_url:'http://media.linkedin.com/mpr/mpr/shrink_80_80/p/2/000/005/0a8/044278d.jpg'}
]);
scope.init();
});

24
jsTestDriver-jquery.conf Normal file
View file

@ -0,0 +1,24 @@
server: http://localhost:9876
load:
- lib/jasmine/jasmine-0.10.3.js
- lib/jasmine-jstd-adapter/JasmineAdapter.js
- lib/jquery/jquery-1.4.2.js
- test/jquery_alias.js
- src/Angular.js
- src/*.js
- src/scenario/Runner.js
- src/scenario/*.js
- test/testabilityPatch.js
- test/angular-mocks.js
- test/scenario/*.js
- test/*.js
exclude:
- src/angular.prefix
- src/angular.suffix
- src/angular-bootstrap.js
- src/AngularPublic.js
- src/scenario/bootstrap.js
- test/jquery_remove.js

23
jsTestDriver.conf Normal file
View file

@ -0,0 +1,23 @@
server: http://localhost:9876
load:
- lib/jasmine/jasmine-0.10.3.js
- lib/jasmine-jstd-adapter/JasmineAdapter.js
- lib/jquery/jquery-1.4.2.js
- test/jquery_remove.js
- src/Angular.js
- src/*.js
- src/scenario/Runner.js
- src/scenario/*.js
- test/testabilityPatch.js
- test/angular-mocks.js
- test/scenario/*.js
- test/*.js
exclude:
- test/jquery_alias.js
- src/angular.prefix
- src/angular.suffix
- src/angular-bootstrap.js
- src/scenario/bootstrap.js
- src/AngularPublic.js

762
jstd.log Normal file
View file

@ -0,0 +1,762 @@
Apr 8, 2010 2:04:32 PM com.google.jstestdriver.ServerStartupAction run
INFO: Starting server...
Apr 8, 2010 2:04:32 PM org.mortbay.log.Slf4jLog info
INFO: Transparent ProxyServlet @ forward to http://localhost:9876
Apr 8, 2010 2:04:33 PM com.google.jstestdriver.BrowserHunter captureBrowser
INFO: Browser Captured: Firefox version 3.6.3 (1)
Apr 8, 2010 2:04:33 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1?start HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:04:33 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:04:36 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1?start HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:04:43 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:04:53 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:05:04 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:05:14 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:05:24 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:05:34 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:05:44 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:05:54 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:06:04 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:06:14 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:06:24 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:06:34 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:06:44 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:06:54 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:07:04 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:07:14 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:07:24 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:07:34 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Apr 8, 2010 2:07:44 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:07:55 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:08:05 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:08:15 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:08:25 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:08:35 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:08:45 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:08:55 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:09:05 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:09:15 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:09:25 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:09:35 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:09:45 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:09:55 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Apr 8, 2010 2:10:05 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:10:15 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:10:25 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:10:35 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:10:45 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
X-Requested-With: XMLHttpRequest
Content-Length: 0
Content-Type: text/plain; charset=UTF-8
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:10:55 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1?start HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
Apr 8, 2010 2:10:56 PM com.google.jstestdriver.BrowserQueryResponseServlet doPost
FINEST: POST: POST /query/1 HTTP/1.1
Host: misko.i:9876
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://misko.i:9876/slave/1/Runnerstrict.html
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/plain; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 0

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

193
lib/compiler-closure/README Normal file
View file

@ -0,0 +1,193 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Contents
//
The Closure Compiler performs checking, instrumentation, and
optimizations on JavaScript code. The purpose of this README is to
explain how to build and run the Closure Compiler.
The Closure Compiler requires Java 6 or higher.
http://www.java.com/
//
// Building The Closure Compiler
//
There are three ways to get a Closure Compiler executable.
1) Use one we built for you.
Pre-built Closure binaries can be found at
http://code.google.com/p/closure-compiler/downloads/list
2) Check out the source and build it with Apache Ant.
First, check out the full source tree of the Closure Compiler. There
are instructions on how to do this at the project site.
http://code.google.com/p/closure-compiler/source/checkout
Apache Ant is a cross-platform build tool.
http://ant.apache.org/
At the root of the source tree, there is an Ant file named
build.xml. To use it, navigate to the same directory and type the
command
ant jar
This will produce a jar file called "build/compiler.jar".
3) Check out the source and build it with Eclipse.
Eclipse is a cross-platform IDE.
http://www.eclipse.org/
Under Eclipse's File menu, click "New > Project ..." and create a
"Java Project." You will see an options screen. Give the project a
name, select "Create project from existing source," and choose the
root of the checked-out source tree as the existing directory. Verify
that you are using JRE version 6 or higher.
Eclipse can use the build.xml file to discover rules. When you
navigate to the build.xml file, you will see all the build rules in
the "Outline" pane. Run the "jar" rule to build the compiler in
build/compiler.jar.
//
// Running The Closure Compiler
//
Once you have the jar binary, running the Closure Compiler is straightforward.
On the command line, type
java -jar compiler.jar
This starts the compiler in interactive mode. Type
var x = 17 + 25;
then hit "Enter", then hit "Ctrl-Z" (on Windows) or "Ctrl-D" (on Mac or Linux)
and "Enter" again. The Compiler will respond:
var x=42;
The Closure Compiler has many options for reading input from a file,
writing output to a file, checking your code, and running
optimizations. To learn more, type
java -jar compiler.jar --help
You can read more detailed documentation about the many flags at
http://code.google.com/closure/compiler/docs/gettingstarted_app.html
//
// Compiling Multiple Scripts
//
If you have multiple scripts, you should compile them all together with
one compile command.
java -jar compiler.jar --js=in1.js --js=in2.js ... --js_output_file=out.js
The Closure Compiler will concatenate the files in the order they're
passed at the command line.
If you need to compile many, many scripts together, you may start to
run into problems with managing dependencies between scripts. You
should check out the Closure Library. It contains functions for
enforcing dependencies between scripts, and a tool called calcdeps.py
that knows how to give scripts to the Closure Compiler in the right
order.
http://code.google.com/p/closure-library/
//
// Licensing
//
Unless otherwise stated, all source files are licensed under
the Apache License, Version 2.0.
-----
Code under:
src/com/google/javascript/rhino
test/com/google/javascript/rhino
URL: http://www.mozilla.org/rhino
Version: 1.5R3, with heavy modifications
License: Netscape Public License and MPL / GPL dual license
Description: A partial copy of Mozilla Rhino. Mozilla Rhino is an
implementation of JavaScript for the JVM. The JavaScript parser and
the parse tree data structures were extracted and modified
significantly for use by Google's JavaScript compiler.
Local Modifications: The packages have been renamespaced. All code not
relavant to parsing has been removed. A JSDoc parser and static typing
system have been added.
-----
Code in:
lib/libtrunk_rhino_parser_jarjared.jar
URL: http://www.mozilla.org/rhino
Version: Trunk
License: Netscape Public License and MPL / GPL dual license
Description: Mozilla Rhino is an implementation of JavaScript for the JVM.
Local Modifications: None. We've used JarJar to renamespace the code
post-compilation. See:
http://code.google.com/p/jarjar/
-----
Code in:
lib/google_common.jar
URL: http://code.google.com/p/guava-libraries/
Version: Trunk
License: Apache License 2.0
Description: Google's core Java libraries.
Local Modifications: None.
----
Code in:
lib/junit.jar
URL: http://sourceforge.net/projects/junit/
Version: 3.8.1
License: Common Public License 1.0
Description: A framework for writing and running automated tests in Java.
Local Modifications: None.

Binary file not shown.

View file

@ -0,0 +1,111 @@
/**
* @fileoverview Jasmine JsTestDriver Adapter.
* @author ibolmo@gmail.com (Olmo Maldonado)
* @author misko@hevery.com (Misko Hevery)
*/
(function() {
function bind(_this, _function){
return function(){
return _function.call(_this);
};
}
var currentFrame = frame(null, null);
function frame(parent, name){
var caseName = (parent && parent.caseName ? parent.caseName + " " : '') + (name ? name : '');
var frame = {
name: name,
caseName: caseName,
parent: parent,
testCase: TestCase(caseName),
before: [],
after: [],
runBefore: function(){
if (parent) parent.runBefore.apply(this);
for ( var i = 0; i < frame.before.length; i++) {
frame.before[i].apply(this);
}
},
runAfter: function(){
for ( var i = 0; i < frame.after.length; i++) {
frame.after[i].apply(this);
}
if (parent) parent.runAfter.apply(this);
}
};
return frame;
};
jasmine.Env.prototype.describe = (function(describe){
return function(description){
currentFrame = frame(currentFrame, description);
var val = describe.apply(this, arguments);
currentFrame = currentFrame.parent;
return val;
};
})(jasmine.Env.prototype.describe);
var id = 0;
jasmine.Env.prototype.it = (function(it){
return function(desc, itFn){
var self = this;
var spec = it.apply(this, arguments);
var currentSpec = this.currentSpec;
if (!currentSpec.$id) {
currentSpec.$id = id++;
}
var frame = this.jstdFrame = currentFrame;
var name = 'test that it ' + desc;
if (this.jstdFrame.testCase.prototype[name])
throw "Spec with name '" + desc + "' already exists.";
this.jstdFrame.testCase.prototype[name] = function(){
jasmine.getEnv().currentSpec = currentSpec;
frame.runBefore.apply(currentSpec);
try {
itFn.apply(currentSpec);
} finally {
frame.runAfter.apply(currentSpec);
}
};
return spec;
};
})(jasmine.Env.prototype.it);
jasmine.Env.prototype.beforeEach = (function(beforeEach){
return function(beforeEachFunction) {
beforeEach.apply(this, arguments);
currentFrame.before.push(beforeEachFunction);
};
})(jasmine.Env.prototype.beforeEach);
jasmine.Env.prototype.afterEach = (function(afterEach){
return function(afterEachFunction) {
afterEach.apply(this, arguments);
currentFrame.after.push(afterEachFunction);
};
})(jasmine.Env.prototype.afterEach);
jasmine.NestedResults.prototype.addResult = (function(addResult){
return function(result) {
addResult.call(this, result);
if (result.type != 'MessageResult' && !result.passed()) fail(result.message);
};
})(jasmine.NestedResults.prototype.addResult);
// Reset environment with overriden methods.
jasmine.currentEnv_ = null;
jasmine.getEnv();
})();

File diff suppressed because it is too large Load diff

6240
lib/jquery/jquery-1.4.2.js vendored Normal file

File diff suppressed because it is too large Load diff

154
lib/jquery/jquery-1.4.2.min.js vendored Normal file
View file

@ -0,0 +1,154 @@
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

File diff suppressed because one or more lines are too long

BIN
lib/jsl/jsl Executable file

Binary file not shown.

128
lib/jsl/jsl.default.conf Executable file
View file

@ -0,0 +1,128 @@
#
# Configuration File for JavaScript Lint 0.3.0
# Developed by Matthias Miller (http://www.JavaScriptLint.com)
#
# This configuration file can be used to lint a collection of scripts, or to enable
# or disable warnings for scripts that are linted via the command line.
#
### Warnings
# Enable or disable warnings based on requirements.
# Use "+WarningName" to display or "-WarningName" to suppress.
#
-no_return_value # function {0} does not always return a value
+duplicate_formal # duplicate formal argument {0}
-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
+var_hides_arg # variable {0} hides argument
+redeclared_var # redeclaration of {0} {1}
-anon_no_return_value # anonymous function does not always return a value
+missing_semicolon # missing semicolon
+meaningless_block # meaningless block; curly braces have no impact
+comma_separated_stmts # multiple statements separated by commas (use semicolons?)
+unreachable_code # unreachable code
-missing_break # missing break statement
+missing_break_for_last_case # missing break statement for last case in switch
+comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
+useless_void # use of the void type may be unnecessary (void is always undefined)
+multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
+use_of_label # use of label
-block_without_braces # block statement without curly braces
+leading_decimal_point # leading decimal point may indicate a number or an object member
+trailing_decimal_point # trailing decimal point may indicate a number or an object member
+octal_number # leading zeros make an octal number
+nested_comment # nested comment
-misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
+empty_statement # empty statement or extra semicolon
-missing_option_explicit # the "option explicit" control comment is missing
+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
+dup_option_explicit # duplicate "option explicit" control comment
+useless_assign # useless assignment
+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
-missing_default_case # missing default case in switch statement
+duplicate_case_in_switch # duplicate case in switch statements
+default_not_at_end # the default case is not at the end of the switch statement
+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
+useless_comparison # useless comparison; comparing identical expressions
+with_statement # with statement hides undeclared variables; use temporary variable instead
+trailing_comma_in_array # extra comma is not recommended in array initializers
+assign_to_function_call # assignment to a function call
+parseint_missing_radix # parseInt missing radix parameter
### Output format
# Customize the format of the error message.
# __FILE__ indicates current file path
# __FILENAME__ indicates current file name
# __LINE__ indicates current line
# __ERROR__ indicates error message
#
# Visual Studio syntax (default):
+output-format __FILE__(__LINE__): __ERROR__
# Alternative syntax:
#+output-format __FILE__:__LINE__: __ERROR__
### Context
# Show the in-line position of the error.
# Use "+context" to display or "-context" to suppress.
#
+context
### Semicolons
# By default, assignments of an anonymous function to a variable or
# property (such as a function prototype) must be followed by a semicolon.
#
+lambda_assign_requires_semicolon
### Control Comments
# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
# although legacy control comments are enabled by default for backward compatibility.
#
+legacy_control_comments
### JScript Function Extensions
# JScript allows member functions to be defined like this:
# function MyObj() { /*constructor*/ }
# function MyObj.prototype.go() { /*member function*/ }
#
# It also allows events to be attached like this:
# function window::onload() { /*init page*/ }
#
# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
#
-jscript_function_extensions
### Defining identifiers
# By default, "option explicit" is enabled on a per-file basis.
# To enable this for all files, use "+always_use_option_explicit"
-always_use_option_explicit
# Define certain identifiers of which the lint is not aware.
# (Use this in conjunction with the "undeclared identifier" warning.)
#
# Common uses for webpages might be:
#+define window
#+define document
### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
# or "+process Folder\Path\*.htm".
#
+process src/*.js
+process src/scenario/*.js
+process test/*.js
+process test/scenario/*.js

Binary file not shown.

22
lib/nodeserver/server.js Normal file
View file

@ -0,0 +1,22 @@
var sys = require('sys'),
http = require('http'),
fs = require('fs');
http.createServer(function (req, res) {
res.writeHead(200, {});
sys.p('GET ' + req.url);
var file = fs.createReadStream('.' + req.url);
file.addListener('data', bind(res, res.write));
file.addListener('error', function( error ){
sys.p(error);
res.end();
});
file.addListener('close', bind(res, res.end));
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/');
function bind(_this, _fn) {
return function(){
return _fn.apply(_this, arguments);
};
}

File diff suppressed because one or more lines are too long

17
lib/underscore/underscore-min.js vendored Normal file
View file

@ -0,0 +1,17 @@
(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.8";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isNumber(a.length))for(var e=0,f=a.length;e<f;e++)c.call(d,a[e],
e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);var f=
b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(a&&b.isFunction(a.indexOf))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,
d)})};b.pluck=function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,
function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a,
0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d,
e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d=
a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)});
return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);
var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;
if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!a.concat&&!a.substr&&!a.apply&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return a===+a||p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};
b.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.templateSettings={start:"<%",end:"%>",interpolate:/<%=(.+?)%>/g};b.template=function(a,c){var d=b.templateSettings;
a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").replace(new RegExp("'(?=[^"+d.end[0]+"]*"+d.end+")","g"),"\t").split("'").join("\\'").split("\t").join("'").replace(d.interpolate,"',$1,'").split(d.start).join("');").split(d.end).join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;
b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=
function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();

View file

@ -0,0 +1,646 @@
// Underscore.js
// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the terms of the MIT license.
// Portions of Underscore are inspired by or borrowed from Prototype.js,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore
(function() {
// ------------------------- Baseline setup ---------------------------------
// Establish the root object, "window" in the browser, or "global" on the server.
var root = this;
// Save the previous value of the "_" variable.
var previousUnderscore = root._;
// If Underscore is called as a function, it returns a wrapped object that
// can be used OO-style. This wrapper holds altered versions of all the
// underscore functions. Wrapped objects may be chained.
var wrapper = function(obj) { this._wrapped = obj; };
// Establish the object that gets thrown to break out of a loop iteration.
var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__';
// Create a safe reference to the Underscore object for reference below.
var _ = root._ = function(obj) { return new wrapper(obj); };
// Export the Underscore object for CommonJS.
if (typeof exports !== 'undefined') exports._ = _;
// Create quick reference variables for speed access to core prototypes.
var slice = Array.prototype.slice,
unshift = Array.prototype.unshift,
toString = Object.prototype.toString,
hasOwnProperty = Object.prototype.hasOwnProperty,
propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
// Current version.
_.VERSION = '0.5.8';
// ------------------------ Collection Functions: ---------------------------
// The cornerstone, an each implementation.
// Handles objects implementing forEach, arrays, and raw objects.
_.each = function(obj, iterator, context) {
var index = 0;
try {
if (obj.forEach) {
obj.forEach(iterator, context);
} else if (_.isNumber(obj.length)) {
for (var i=0, l=obj.length; i<l; i++) iterator.call(context, obj[i], i, obj);
} else {
var keys = _.keys(obj), l = keys.length;
for (var i=0; i<l; i++) iterator.call(context, obj[keys[i]], keys[i], obj);
}
} catch(e) {
if (e != breaker) throw e;
}
return obj;
};
// Return the results of applying the iterator to each element. Use JavaScript
// 1.6's version of map, if possible.
_.map = function(obj, iterator, context) {
if (obj && _.isFunction(obj.map)) return obj.map(iterator, context);
var results = [];
_.each(obj, function(value, index, list) {
results.push(iterator.call(context, value, index, list));
});
return results;
};
// Reduce builds up a single result from a list of values. Also known as
// inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible.
_.reduce = function(obj, memo, iterator, context) {
if (obj && _.isFunction(obj.reduce)) return obj.reduce(_.bind(iterator, context), memo);
_.each(obj, function(value, index, list) {
memo = iterator.call(context, memo, value, index, list);
});
return memo;
};
// The right-associative version of reduce, also known as foldr. Uses
// JavaScript 1.8's version of reduceRight, if available.
_.reduceRight = function(obj, memo, iterator, context) {
if (obj && _.isFunction(obj.reduceRight)) return obj.reduceRight(_.bind(iterator, context), memo);
var reversed = _.clone(_.toArray(obj)).reverse();
_.each(reversed, function(value, index) {
memo = iterator.call(context, memo, value, index, obj);
});
return memo;
};
// Return the first value which passes a truth test.
_.detect = function(obj, iterator, context) {
var result;
_.each(obj, function(value, index, list) {
if (iterator.call(context, value, index, list)) {
result = value;
_.breakLoop();
}
});
return result;
};
// Return all the elements that pass a truth test. Use JavaScript 1.6's
// filter(), if it exists.
_.select = function(obj, iterator, context) {
if (obj && _.isFunction(obj.filter)) return obj.filter(iterator, context);
var results = [];
_.each(obj, function(value, index, list) {
iterator.call(context, value, index, list) && results.push(value);
});
return results;
};
// Return all the elements for which a truth test fails.
_.reject = function(obj, iterator, context) {
var results = [];
_.each(obj, function(value, index, list) {
!iterator.call(context, value, index, list) && results.push(value);
});
return results;
};
// Determine whether all of the elements match a truth test. Delegate to
// JavaScript 1.6's every(), if it is present.
_.all = function(obj, iterator, context) {
iterator = iterator || _.identity;
if (obj && _.isFunction(obj.every)) return obj.every(iterator, context);
var result = true;
_.each(obj, function(value, index, list) {
if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
});
return result;
};
// Determine if at least one element in the object matches a truth test. Use
// JavaScript 1.6's some(), if it exists.
_.any = function(obj, iterator, context) {
iterator = iterator || _.identity;
if (obj && _.isFunction(obj.some)) return obj.some(iterator, context);
var result = false;
_.each(obj, function(value, index, list) {
if (result = iterator.call(context, value, index, list)) _.breakLoop();
});
return result;
};
// Determine if a given value is included in the array or object,
// based on '==='.
_.include = function(obj, target) {
if (obj && _.isFunction(obj.indexOf)) return _.indexOf(obj, target) != -1;
var found = false;
_.each(obj, function(value) {
if (found = value === target) _.breakLoop();
});
return found;
};
// Invoke a method with arguments on every item in a collection.
_.invoke = function(obj, method) {
var args = _.rest(arguments, 2);
return _.map(obj, function(value) {
return (method ? value[method] : value).apply(value, args);
});
};
// Convenience version of a common use case of map: fetching a property.
_.pluck = function(obj, key) {
return _.map(obj, function(value){ return value[key]; });
};
// Return the maximum item or (item-based computation).
_.max = function(obj, iterator, context) {
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
var result = {computed : -Infinity};
_.each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
computed >= result.computed && (result = {value : value, computed : computed});
});
return result.value;
};
// Return the minimum element (or element-based computation).
_.min = function(obj, iterator, context) {
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
var result = {computed : Infinity};
_.each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
computed < result.computed && (result = {value : value, computed : computed});
});
return result.value;
};
// Sort the object's values by a criteria produced by an iterator.
_.sortBy = function(obj, iterator, context) {
return _.pluck(_.map(obj, function(value, index, list) {
return {
value : value,
criteria : iterator.call(context, value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
}), 'value');
};
// Use a comparator function to figure out at what index an object should
// be inserted so as to maintain order. Uses binary search.
_.sortedIndex = function(array, obj, iterator) {
iterator = iterator || _.identity;
var low = 0, high = array.length;
while (low < high) {
var mid = (low + high) >> 1;
iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
}
return low;
};
// Convert anything iterable into a real, live array.
_.toArray = function(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
if (_.isArray(iterable)) return iterable;
if (_.isArguments(iterable)) return slice.call(iterable);
return _.values(iterable);
};
// Return the number of elements in an object.
_.size = function(obj) {
return _.toArray(obj).length;
};
// -------------------------- Array Functions: ------------------------------
// Get the first element of an array. Passing "n" will return the first N
// values in the array. Aliased as "head". The "guard" check allows it to work
// with _.map.
_.first = function(array, n, guard) {
return n && !guard ? slice.call(array, 0, n) : array[0];
};
// Returns everything but the first entry of the array. Aliased as "tail".
// Especially useful on the arguments object. Passing an "index" will return
// the rest of the values in the array from that index onward. The "guard"
//check allows it to work with _.map.
_.rest = function(array, index, guard) {
return slice.call(array, _.isUndefined(index) || guard ? 1 : index);
};
// Get the last element of an array.
_.last = function(array) {
return array[array.length - 1];
};
// Trim out all falsy values from an array.
_.compact = function(array) {
return _.select(array, function(value){ return !!value; });
};
// Return a completely flattened version of an array.
_.flatten = function(array) {
return _.reduce(array, [], function(memo, value) {
if (_.isArray(value)) return memo.concat(_.flatten(value));
memo.push(value);
return memo;
});
};
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
var values = _.rest(arguments);
return _.select(array, function(value){ return !_.include(values, value); });
};
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
_.uniq = function(array, isSorted) {
return _.reduce(array, [], function(memo, el, i) {
if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo.push(el);
return memo;
});
};
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersect = function(array) {
var rest = _.rest(arguments);
return _.select(_.uniq(array), function(item) {
return _.all(rest, function(other) {
return _.indexOf(other, item) >= 0;
});
});
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.zip = function() {
var args = _.toArray(arguments);
var length = _.max(_.pluck(args, 'length'));
var results = new Array(length);
for (var i=0; i<length; i++) results[i] = _.pluck(args, String(i));
return results;
};
// If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
// we need this function. Return the position of the first occurence of an
// item in an array, or -1 if the item is not included in the array.
_.indexOf = function(array, item) {
if (array.indexOf) return array.indexOf(item);
for (var i=0, l=array.length; i<l; i++) if (array[i] === item) return i;
return -1;
};
// Provide JavaScript 1.6's lastIndexOf, delegating to the native function,
// if possible.
_.lastIndexOf = function(array, item) {
if (array.lastIndexOf) return array.lastIndexOf(item);
var i = array.length;
while (i--) if (array[i] === item) return i;
return -1;
};
// Generate an integer Array containing an arithmetic progression. A port of
// the native Python range() function. See:
// http://docs.python.org/library/functions.html#range
_.range = function(start, stop, step) {
var a = _.toArray(arguments);
var solo = a.length <= 1;
var start = solo ? 0 : a[0], stop = solo ? a[0] : a[1], step = a[2] || 1;
var len = Math.ceil((stop - start) / step);
if (len <= 0) return [];
var range = new Array(len);
for (var i = start, idx = 0; true; i += step) {
if ((step > 0 ? i - stop : stop - i) >= 0) return range;
range[idx++] = i;
}
};
// ----------------------- Function Functions: ------------------------------
// Create a function bound to a given object (assigning 'this', and arguments,
// optionally). Binding with arguments is also known as 'curry'.
_.bind = function(func, obj) {
var args = _.rest(arguments, 2);
return function() {
return func.apply(obj || root, args.concat(_.toArray(arguments)));
};
};
// Bind all of an object's methods to that object. Useful for ensuring that
// all callbacks defined on an object belong to it.
_.bindAll = function(obj) {
var funcs = _.rest(arguments);
if (funcs.length == 0) funcs = _.functions(obj);
_.each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
return obj;
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = _.rest(arguments, 2);
return setTimeout(function(){ return func.apply(func, args); }, wait);
};
// Defers a function, scheduling it to run after the current call stack has
// cleared.
_.defer = function(func) {
return _.delay.apply(_, [func, 1].concat(_.rest(arguments)));
};
// Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
return function() {
var args = [func].concat(_.toArray(arguments));
return wrapper.apply(wrapper, args);
};
};
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
var funcs = _.toArray(arguments);
return function() {
var args = _.toArray(arguments);
for (var i=funcs.length-1; i >= 0; i--) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
// ------------------------- Object Functions: ------------------------------
// Retrieve the names of an object's properties.
_.keys = function(obj) {
if (_.isArray(obj)) return _.range(0, obj.length);
var keys = [];
for (var key in obj) if (hasOwnProperty.call(obj, key)) keys.push(key);
return keys;
};
// Retrieve the values of an object's properties.
_.values = function(obj) {
return _.map(obj, _.identity);
};
// Return a sorted list of the function names available in Underscore.
_.functions = function(obj) {
return _.select(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
};
// Extend a given object with all of the properties in a source object.
_.extend = function(destination, source) {
for (var property in source) destination[property] = source[property];
return destination;
};
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (_.isArray(obj)) return obj.slice(0);
return _.extend({}, obj);
};
// Invokes interceptor with the obj, and then returns obj.
// The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain.
_.tap = function(obj, interceptor) {
interceptor(obj);
return obj;
};
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
// Check object identity.
if (a === b) return true;
// Different types?
var atype = typeof(a), btype = typeof(b);
if (atype != btype) return false;
// Basic equality test (watch out for coercions).
if (a == b) return true;
// One is falsy and the other truthy.
if ((!a && b) || (a && !b)) return false;
// One of them implements an isEqual()?
if (a.isEqual) return a.isEqual(b);
// Check dates' integer values.
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
// Both are NaN?
if (_.isNaN(a) && _.isNaN(b)) return true;
// Compare regular expressions.
if (_.isRegExp(a) && _.isRegExp(b))
return a.source === b.source &&
a.global === b.global &&
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline;
// If a is not an object by this point, we can't handle it.
if (atype !== 'object') return false;
// Check for different array lengths before comparing contents.
if (a.length && (a.length !== b.length)) return false;
// Nothing else worked, deep compare the contents.
var aKeys = _.keys(a), bKeys = _.keys(b);
// Different object sizes?
if (aKeys.length != bKeys.length) return false;
// Recursive comparison of contents.
for (var key in a) if (!_.isEqual(a[key], b[key])) return false;
return true;
};
// Is a given array or object empty?
_.isEmpty = function(obj) {
return _.keys(obj).length == 0;
};
// Is a given value a DOM element?
_.isElement = function(obj) {
return !!(obj && obj.nodeType == 1);
};
// Is a given value an array?
_.isArray = function(obj) {
return !!(obj && obj.concat && obj.unshift);
};
// Is a given variable an arguments object?
_.isArguments = function(obj) {
return obj && _.isNumber(obj.length) && !obj.concat && !obj.substr && !obj.apply && !propertyIsEnumerable.call(obj, 'length');
};
// Is a given value a function?
_.isFunction = function(obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
// Is a given value a string?
_.isString = function(obj) {
return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
};
// Is a given value a number?
_.isNumber = function(obj) {
return (obj === +obj) || (toString.call(obj) === '[object Number]');
};
// Is a given value a date?
_.isDate = function(obj) {
return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
};
// Is the given value a regular expression?
_.isRegExp = function(obj) {
return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
};
// Is the given value NaN -- this one is interesting. NaN != NaN, and
// isNaN(undefined) == true, so we make sure it's a number first.
_.isNaN = function(obj) {
return _.isNumber(obj) && isNaN(obj);
};
// Is a given value equal to null?
_.isNull = function(obj) {
return obj === null;
};
// Is a given variable undefined?
_.isUndefined = function(obj) {
return typeof obj == 'undefined';
};
// -------------------------- Utility Functions: ----------------------------
// Run Underscore.js in noConflict mode, returning the '_' variable to its
// previous owner. Returns a reference to the Underscore object.
_.noConflict = function() {
root._ = previousUnderscore;
return this;
};
// Keep the identity function around for default iterators.
_.identity = function(value) {
return value;
};
// Break out of the middle of an iteration.
_.breakLoop = function() {
throw breaker;
};
// Generate a unique integer id (unique within the entire client session).
// Useful for temporary DOM ids.
var idCounter = 0;
_.uniqueId = function(prefix) {
var id = idCounter++;
return prefix ? prefix + id : id;
};
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
start : '<%',
end : '%>',
interpolate : /<%=(.+?)%>/g
};
// JavaScript templating a-la ERB, pilfered from John Resig's
// "Secrets of the JavaScript Ninja", page 83.
// Single-quote fix from Rick Strahl's version.
_.template = function(str, data) {
var c = _.templateSettings;
var fn = new Function('obj',
'var p=[],print=function(){p.push.apply(p,arguments);};' +
'with(obj){p.push(\'' +
str.replace(/[\r\t\n]/g, " ")
.replace(new RegExp("'(?=[^"+c.end[0]+"]*"+c.end+")","g"),"\t")
.split("'").join("\\'")
.split("\t").join("'")
.replace(c.interpolate, "',$1,'")
.split(c.start).join("');")
.split(c.end).join("p.push('")
+ "');}return p.join('');");
return data ? fn(data) : fn;
};
// ------------------------------- Aliases ----------------------------------
_.forEach = _.each;
_.foldl = _.inject = _.reduce;
_.foldr = _.reduceRight;
_.filter = _.select;
_.every = _.all;
_.some = _.any;
_.head = _.first;
_.tail = _.rest;
_.methods = _.functions;
// ------------------------ Setup the OOP Wrapper: --------------------------
// Helper function to continue chaining intermediate results.
var result = function(obj, chain) {
return chain ? _(obj).chain() : obj;
};
// Add all of the Underscore functions to the wrapper object.
_.each(_.functions(_), function(name) {
var method = _[name];
wrapper.prototype[name] = function() {
var args = _.toArray(arguments);
unshift.call(args, this._wrapped);
return result(method.apply(_, args), this._chain);
};
});
// Add all mutator Array functions to the wrapper.
_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = Array.prototype[name];
wrapper.prototype[name] = function() {
method.apply(this._wrapped, arguments);
return result(this._wrapped, this._chain);
};
});
// Add all accessor Array functions to the wrapper.
_.each(['concat', 'join', 'slice'], function(name) {
var method = Array.prototype[name];
wrapper.prototype[name] = function() {
return result(method.apply(this._wrapped, arguments), this._chain);
};
});
// Start chaining a wrapped Underscore object.
wrapper.prototype.chain = function() {
this._chain = true;
return this;
};
// Extracts the result from a wrapped and chained object.
wrapper.prototype.value = function() {
return this._wrapped;
};
})();

7
lib/underscore/update.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
underscore=$(dirname $0)
github='http://github.com/documentcloud/underscore/raw/master'
wget $github/underscore-min.js -O $underscore/underscore-min.js
wget $github/underscore.js -O $underscore/underscore.js

View file

@ -0,0 +1,142 @@
/**
*
* Base64 encode / decode
* http://www.webtoolkit.info/
*
**/
var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
// public method for encoding
encode : function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
// public method for decoding
decode : function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = this._keyStr.indexOf(input.charAt(i++));
enc2 = this._keyStr.indexOf(input.charAt(i++));
enc3 = this._keyStr.indexOf(input.charAt(i++));
enc4 = this._keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = Base64._utf8_decode(output);
return output;
},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
};

1
nodeserver.sh Executable file
View file

@ -0,0 +1 @@
node lib/nodeserver/server.js

View file

@ -0,0 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../angular-scenario.js"></script>
<script type="text/javascript" src="widgets-scenario.js"></script>
</head>
<body>
</body>
</html>

9
scenario/Runner.html Normal file
View file

@ -0,0 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../src/scenario/bootstrap.js"></script>
<script type="text/javascript" src="widgets-scenario.js"></script>
</head>
<body>
</body>
</html>

View file

@ -0,0 +1,6 @@
<div ng-controller="AccountController">
account page goes here!
<input type="text" name="name" value="misko"/>
<button ng-click="hello()">hello</button>
</div>

34
scenario/application.html Normal file
View file

@ -0,0 +1,34 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css"></link>
<script type="text/javascript" src="../src/angular-bootstrap.js#autobind"></script>
<script>
function AccountController(){
}
AccountController.prototype = {
hello: function(){
alert(this.name);
}
};
</script>
</head>
<body ng-init="$window.$scope = this">
[ <a href="#login">login</a>
| <a href="#account">account</a>
]
<ng:switch on="$location.hashPath">
<div ng-switch-when="login">login screen</div>
<ng:include ng-switch-when="account" src="'application-account.html'"></ng:include>
</ng:switch>
(( input name ))
<pre>$location={{$location}}</pre>
</body>
</html>

View file

@ -0,0 +1,4 @@
[
{ name: 'Misko', favorite: ['water melon', 'persimmon', 'passion fruit'] },
{ name: 'Lenka', favorite: ['strawberry'] }
]

View file

@ -0,0 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../../src/angular-bootstrap.js#autobind"></script>
</head>
<body ng:init="$window.$scope = this; People = $resource('People.json')">
<button ng-click="people = People.query()">Load People</button>
<pre>people = {{people}}</pre>
</body>
</html>

View file

@ -0,0 +1,19 @@
angular.scenarioDef.datastore = {
$before:[
{Given:"dataset",
dataset:{
Book:[{$id:'moby', name:"Moby Dick"},
{$id:'gadsby', name:'Great Gadsby'}]
}
},
{Given:"browser", at:"datastore.html#book=moby"},
],
checkLoadBook:[
{Then:"drainRequestQueue"},
{Then:"text", at:"{{book.$id}}", should_be:"moby"},
{Then:"text", at:"li[$index=0] {{book.name}}", should_be:"Great Gahdsby"},
{Then:"text", at:"li[$index=0] {{book.name}}", should_be:"Moby Dick"},
]
};

17
scenario/datastore.html Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="../lib/underscore/underscore.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery-1.3.2.js"></script>
<script type="text/javascript" src="../src/angular-bootstrap.js"></script>
<script type="text/javascript">
$(document).ready(function(){angular.compile(document).init();});
</script>
</head>
<body ng-entity="book=Book" ng-init="books=Book.all()">
<p>{{book.$id}}</p>
<li ng-repeat="book in books.$orderBy('name')">
<li>{{book.name}}</li>
</li>
</body>
</html>

33
scenario/perf.html Normal file
View file

@ -0,0 +1,33 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css"/>
<script type="text/javascript" src="../src/angular-bootstrap.js#autobind"></script>
<script type="text/javascript">
function PerfCntl(){}
PerfCntl.prototype = {
createItems: function(){
var items = [];
for ( var i = 0; i < 1000; i++) {
var item = {
name: "" + Math.random(),
parts: [Math.random(), Math.random()]
};
items.push(item);
}
return items;
}
};
</script>
</head>
<body ng:init="$window.$scope = this; items = createItems()" ng-controller="PerfCntl">
<input type="text" name="text"/>
<hr/>
<ul>
<li Xng-repeat="item in items.$filter('').$orderBy('name')"
ng-repeat="item in items">
{{item.name}} <a href="#{{item.name}}">{{item.parts.join(', ')}}</a>
</li>
</ul>
</body>
</html>

7
scenario/style.css Normal file
View file

@ -0,0 +1,7 @@
th {
text-align: left;
}
tr {
border: 1px solid black;
}

View file

@ -0,0 +1,25 @@
describe('widgets', function(){
it('should verify that basic widgets work', function(){
browser.navigateTo('widgets.html');
expect('{{text.basic}}').toEqual('');
input('text.basic').enter('John');
expect('{{text.basic}}').toEqual('John');
expect('{{text.password}}').toEqual('');
input('text.password').enter('secret');
expect('{{text.password}}').toEqual('secret');
expect('{{text.hidden}}').toEqual('hiddenValue');
expect('{{gender}}').toEqual('male');
input('gender').select('female');
input('gender').isChecked('female');
expect('{{gender}}').toEqual('female');
// expect('{{tea}}').toBeChecked();
// input('gender').select('female');
// expect('{{gender}}').toEqual('female');
});
});

View file

@ -0,0 +1,49 @@
angular.scenarioDef.widgets = {
$before:[
{Given:"browser", at:"widgets.html"}
],
checkWidgetBinding:[
{Then:"text", at:"{{text.basic}}", should_be:""},
{When:"enter", text:"John", at:":input[name=text.basic]"},
{Then:"text", at:"{{text.basic}}", should_be:"John"},
{Then:"text", at:"{{gender}}", should_be:"male"},
{When:"click", at:"input:radio[value=female]"},
{Then:"text", at:"{{gender}}", should_be:"female"},
{Then:"text", at:"{{tea}}", should_be:"on"},
{When:"click", at:"input[name=tea]"},
{Then:"text", at:"{{tea}}", should_be:""},
{Then:"text", at:"{{coffee}}", should_be:""},
{When:"click", at:"input[name=coffee]"},
{Then:"text", at:"{{coffee}}", should_be:"on"},
{Then:"text", at:"{{count}}", should_be:0},
{When:"click", at:"form :button"},
{When:"click", at:"form :submit"},
{When:"click", at:"form :image"},
{Then:"text", at:"{{count}}", should_be:3},
{Then:"text", at:"{{select}}", should_be:"A"},
{When:"select", at:"select[name=select]", option:"B"},
{Then:"text", at:"{{select}}", should_be:"B"},
{Then:"text", at:"{{multiple}}", should_be:"[]"},
{When:"select", at:"select[name=multiple]", option:"A"},
{Then:"text", at:"{{multiple}}", should_be:["A"]},
{When:"select", at:"select[name=multiple]", option:"B"},
{Then:"text", at:"{{multiple}}", should_be:["A", "B"]},
{When:"select", at:"select[name=multiple]", option:"A"},
{Then:"text", at:"{{multiple}}", should_be:["B"]},
{Then:"text", at:"{{hidden}}", should_be:"hiddenValue"},
{Then:"text", at:"{{password}}", should_be:"passwordValue"},
{When:"enter", text:"reset", at:":input[name=password]"},
{Then:"text", at:"{{password}}", should_be:"reset"},
],
checkNewWidgetEmpty:[
{Then:"text", at:"{{name}}", should_be:""},
]
};

98
scenario/widgets.html Normal file
View file

@ -0,0 +1,98 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css"/>
<script type="text/javascript" src="../src/angular-bootstrap.js#autobind"></script>
</head>
<body ng:init="$window.$scope = this">
<table>
<tr>
<th width="330">Description</th>
<th>Test</th>
<th>Result</th>
</tr>
<tr><th colspan="3">Input text field</th></tr>
<tr>
<td>basic</td>
<td>
<input type="text" name="text.basic"/>
</td>
<td>text.basic={{text.basic}}</td>
</tr>
<tr>
<td>password</td>
<td><input type="password" name="text.password" /></td>
<td>text.password={{text.password}}</td>
</tr>
<tr>
<td>hidden</td>
<td><input type="hidden" name="text.hidden" value="hiddenValue" /></td>
<td>text.hidden={{text.hidden}}</td>
</tr>
<tr><th colspan="3">Input selection field</th></tr>
<tr>
<td>radio</td>
<td>
<input type="radio" name="gender" value="female"/> Female <br/>
<input type="radio" name="gender" value="male" checked="checked"/> Male
</td>
<td>gender={{gender}}</td>
</tr>
<tr>
<td>checkbox</td>
<td>
<input type="checkbox" name="checkbox.tea" checked value="on"/> Tea<br/>
<input type="checkbox" name="checkbox.coffee" value="on"/> Coffe
</td>
<td>
<pre>checkbox={{checkbox}}</pre>
</td>
</tr>
<tr>
<td>select</td>
<td>
<select name="select">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</td>
<td>select={{select}}</td>
</tr>
<tr>
<td>multiselect</td>
<td>
<select name="multiselect" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</td>
<td>multiselect={{multiselect}}</td>
</tr>
<tr><th colspan="3">Buttons</th></tr>
<tr>
<td>ng-change<br/>ng-click</td>
<td ng:init="button.count = 0">
<form>
<input type="button" value="button" ng-change="button.count = button.count + 1"/> <br/>
<input type="submit" value="submit" ng-change="button.count = button.count + 1"/><br/>
<input type="image" src="" ng-change="button.count = button.count + 1"/><br/>
<a href="" ng:click="button.count = button.count + 1">action</a>
</form>
</td>
<td>button={{button}}</td>
</tr>
<tr><th colspan="3">Repeaters</th></tr>
<tr>
<td>ng-repeat</td>
<td>
<ul>
<li ng-repeat="name in ['misko', 'adam']">{{name}}</li>
</ul>
</td>
<td></td>
</tr>
</table>
</body>
</html>

1
server.sh Executable file
View file

@ -0,0 +1 @@
java -jar lib/jstestdriver/JsTestDriver.jar --port 9876

401
src/Angular.js Normal file
View file

@ -0,0 +1,401 @@
////////////////////////////////////
if (typeof document.getAttribute == 'undefined')
document.getAttribute = function() {};
if (!window['console']) window['console']={'log':noop, 'error':noop};
var consoleNode,
PRIORITY_FIRST = -99999,
PRIORITY_WATCH = -1000,
PRIORITY_LAST = 99999,
PRIORITY = {'FIRST': PRIORITY_FIRST, 'LAST': PRIORITY_LAST, 'WATCH':PRIORITY_WATCH},
NOOP = 'noop',
NG_EXCEPTION = 'ng-exception',
NG_VALIDATION_ERROR = 'ng-validation-error',
jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy
_ = window['_'],
msie = !!/(msie) ([\w.]+)/.exec(lowercase(navigator.userAgent)),
jqLite = jQuery || jqLiteWrap,
slice = Array.prototype.slice,
angular = window['angular'] || (window['angular'] = {}),
angularTextMarkup = extensionMap(angular, 'textMarkup'),
angularAttrMarkup = extensionMap(angular, 'attrMarkup'),
angularDirective = extensionMap(angular, 'directive'),
angularWidget = extensionMap(angular, 'widget'),
angularValidator = extensionMap(angular, 'validator'),
angularFilter = extensionMap(angular, 'filter'),
angularFormatter = extensionMap(angular, 'formatter'),
angularService = extensionMap(angular, 'service'),
angularCallbacks = extensionMap(angular, 'callbacks'),
nodeName;
function angularAlert(){
log(arguments); window.alert.apply(window, arguments);
}
function foreach(obj, iterator, context) {
var key;
if (obj) {
if (isFunction(obj)){
for (key in obj) {
if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
iterator.call(context, obj[key], key);
}
}
} else if (obj.forEach) {
obj.forEach(iterator, context);
} else if (isObject(obj) && isNumber(obj.length)) {
for (key = 0; key < obj.length; key++)
iterator.call(context, obj[key], key);
} else {
for (key in obj)
iterator.call(context, obj[key], key);
}
}
return obj;
}
function foreachSorted(obj, iterator, context) {
var keys = [];
for (var key in obj) keys.push(key);
keys.sort();
for ( var i = 0; i < keys.length; i++) {
iterator.call(context, obj[keys[i]], keys[i]);
}
return keys;
}
function extend(dst) {
foreach(arguments, function(obj){
if (obj !== dst) {
foreach(obj, function(value, key){
dst[key] = value;
});
}
});
return dst;
}
function noop() {}
function identity($) {return $;}
function extensionMap(angular, name) {
var extPoint;
return angular[name] || (extPoint = angular[name] = function (name, fn, prop){
if (isDefined(fn)) {
extPoint[name] = extend(fn, prop || {});
}
return extPoint[name];
});
}
function jqLiteWrap(element) {
// for some reasons the parentNode of an orphan looks like null but its typeof is object.
if (element) {
if (isString(element)) {
var div = document.createElement('div');
div.innerHTML = element;
element = new JQLite(div.childNodes);
} else if (!(element instanceof JQLite) && isElement(element)) {
element = new JQLite(element);
}
}
return element;
}
function isUndefined(value){ return typeof value == 'undefined'; }
function isDefined(value){ return typeof value != 'undefined'; }
function isObject(value){ return typeof value == 'object';}
function isString(value){ return typeof value == 'string';}
function isNumber(value){ return typeof value == 'number';}
function isArray(value) { return value instanceof Array; }
function isFunction(value){ return typeof value == 'function';}
function isTextNode(node) { return nodeName(node) == '#text'; }
function lowercase(value){ return isString(value) ? value.toLowerCase() : value; }
function uppercase(value){ return isString(value) ? value.toUpperCase() : value; }
function trim(value) { return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value; }
function isElement(node) {
return node && (node.nodeName || node instanceof JQLite || (jQuery && node instanceof jQuery));
}
function HTML(html) {
this.html = html;
}
if (msie) {
nodeName = function(element) {
element = element[0] || element;
return (element.scopeName && element.scopeName != 'HTML' ) ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
};
} else {
nodeName = function(element) {
return (element[0] || element).nodeName;
};
}
function isVisible(element) {
var rect = element[0].getBoundingClientRect(),
width = (rect.width || (rect.right||0 - rect.left||0)),
height = (rect.height || (rect.bottom||0 - rect.top||0));
return width>0 && height>0;
}
function map(obj, iterator, context) {
var results = [];
foreach(obj, function(value, index, list) {
results.push(iterator.call(context, value, index, list));
});
return results;
}
function size(obj) {
var size = 0;
if (obj) {
if (isNumber(obj.length)) {
return obj.length;
} else if (isObject(obj)){
for (key in obj)
size++;
}
}
return size;
}
function includes(array, obj) {
for ( var i = 0; i < array.length; i++) {
if (obj === array[i]) return true;
}
return false;
}
function indexOf(array, obj) {
for ( var i = 0; i < array.length; i++) {
if (obj === array[i]) return i;
}
return -1;
}
function log(a, b, c){
var console = window['console'];
switch(arguments.length) {
case 1:
console['log'](a);
break;
case 2:
console['log'](a, b);
break;
default:
console['log'](a, b, c);
break;
}
}
function error(a, b, c){
var console = window['console'];
switch(arguments.length) {
case 1:
console['error'](a);
break;
case 2:
console['error'](a, b);
break;
default:
console['error'](a, b, c);
break;
}
}
function consoleLog(level, objs) {
var log = document.createElement("div");
log.className = level;
var msg = "";
var sep = "";
for ( var i = 0; i < objs.length; i++) {
var obj = objs[i];
msg += sep + (typeof obj == 'string' ? obj : toJson(obj));
sep = " ";
}
log.appendChild(document.createTextNode(msg));
consoleNode.appendChild(log);
}
function isLeafNode (node) {
if (node) {
switch (node.nodeName) {
case "OPTION":
case "PRE":
case "TITLE":
return true;
}
}
return false;
}
function copy(source, destination){
if (!destination) {
if (source) {
if (isArray(source)) {
return copy(source, []);
} else if (isObject(source)) {
return copy(source, {});
}
}
return source;
} else {
if (isArray(source)) {
while(destination.length) {
destination.pop();
}
for ( var i = 0; i < source.length; i++) {
destination.push(copy(source[i]));
}
} else {
foreach(destination, function(value, key){
delete destination[key];
});
for ( var key in source) {
destination[key] = copy(source[key]);
}
}
return destination;
}
}
function setHtml(node, html) {
if (isLeafNode(node)) {
if (msie) {
node.innerText = html;
} else {
node.textContent = html;
}
} else {
node.innerHTML = html;
}
}
function escapeHtml(html) {
if (!html || !html.replace)
return html;
return html.
replace(/&/g, '&amp;').
replace(/</g, '&lt;').
replace(/>/g, '&gt;');
}
function isRenderableElement(element) {
var name = element && element[0] && element[0].nodeName;
return name && name.charAt(0) != '#' &&
!includes(['TR', 'COL', 'COLGROUP', 'TBODY', 'THEAD', 'TFOOT'], name);
}
function elementError(element, type, error) {
while (!isRenderableElement(element)) {
element = element.parent() || jqLite(document.body);
}
if (element[0]['$NG_ERROR'] !== error) {
element[0]['$NG_ERROR'] = error;
if (error) {
element.addClass(type);
element.attr(type, error);
} else {
element.removeClass(type);
element.removeAttr(type);
}
}
}
function escapeAttr(html) {
if (!html || !html.replace)
return html;
return html.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g,
'&quot;');
}
function bind(_this, _function) {
if (!isFunction(_function))
throw "Not a function!";
var curryArgs = slice.call(arguments, 2, arguments.length);
return function() {
return _function.apply(_this, curryArgs.concat(slice.call(arguments, 0, arguments.length)));
};
}
function outerHTML(node) {
var temp = document.createElement('div');
temp.appendChild(node);
var outerHTML = temp.innerHTML;
temp.removeChild(node);
return outerHTML;
}
function toBoolean(value) {
if (value && value.length !== 0) {
var v = lowercase("" + value);
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == '[]');
} else {
value = false;
}
return value;
}
function merge(src, dst) {
for ( var key in src) {
var value = dst[key];
var type = typeof value;
if (type == 'undefined') {
dst[key] = fromJson(toJson(src[key]));
} else if (type == 'object' && value.constructor != array &&
key.substring(0, 1) != "$") {
merge(src[key], value);
}
}
}
function compile(element, parentScope, overrides) {
var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget),
$element = jqLite(element),
parent = extend({}, parentScope);
parent.$element = $element;
return compiler.compile($element)($element, parent, overrides);
}
/////////////////////////////////////////////////
function parseKeyValue(keyValue) {
var obj = {}, key_value, key;
foreach((keyValue || "").split('&'), function(keyValue){
if (keyValue) {
key_value = keyValue.split('=');
key = decodeURIComponent(key_value[0]);
obj[key] = key_value[1] ? decodeURIComponent(key_value[1]) : true;
}
});
return obj;
}
function toKeyValue(obj) {
var parts = [];
foreach(obj, function(value, key){
parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
});
return parts.length ? parts.join('&') : '';
}
function angularInit(config){
if (config.autobind) {
var scope = compile(window.document, null, {'$config':config});
// TODO default to the source of angular.js
scope.$browser.addCss('css/angular.css');
scope.$init();
}
}
function angularJsConfig(document) {
var filename = /(.*)\/angular(-(.*))?.js(#(.*))?/,
scripts = document.getElementsByTagName("SCRIPT"),
match;
for(var j = 0; j < scripts.length; j++) {
match = (scripts[j].src || "").match(filename);
if (match) {
return match[5];
}
}
return "";
}

29
src/AngularPublic.js Normal file
View file

@ -0,0 +1,29 @@
var browserSingleton;
angularService('$browser', function browserFactory(){
if (!browserSingleton) {
browserSingleton = new Browser(window.location, window.document);
browserSingleton.startUrlWatcher();
browserSingleton.bind();
}
return browserSingleton;
});
extend(angular, {
'element': jqLite,
'compile': compile,
'scope': createScope,
'copy': copy,
'extend': extend,
'foreach': foreach,
'noop':noop,
'bind':bind,
'identity':identity,
'isUndefined': isUndefined,
'isDefined': isDefined,
'isString': isString,
'isFunction': isFunction,
'isObject': isObject,
'isNumber': isNumber,
'isArray': isArray
});

130
src/Browser.js Normal file
View file

@ -0,0 +1,130 @@
//////////////////////////////
// Browser
//////////////////////////////
function Browser(location, document) {
this.delay = 50;
this.expectedUrl = location.href;
this.urlListeners = [];
this.hoverListener = noop;
this.isMock = false;
this.outstandingRequests = { count: 0, callbacks:[]};
this.XHR = window.XMLHttpRequest || function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
this.setTimeout = function(fn, delay) {
window.setTimeout(fn, delay);
};
this.location = location;
this.document = jqLite(document);
this.body = jqLite(document.body);
}
Browser.prototype = {
bind: function() {
var self = this;
self.document.bind("mouseover", function(event){
self.hoverListener(jqLite(msie ? event.srcElement : event.target), true);
return true;
});
self.document.bind("mouseleave mouseout click dblclick keypress keyup", function(event){
self.hoverListener(jqLite(event.target), false);
return true;
});
},
hover: function(hoverListener) {
this.hoverListener = hoverListener;
},
addCss: function(url) {
var doc = this.document[0],
head = jqLite(doc.getElementsByTagName('head')[0]),
link = jqLite(doc.createElement('link'));
link.attr('rel', 'stylesheet');
link.attr('type', 'text/css');
link.attr('href', url);
head.append(link);
},
xhr: function(method, url, post, callback){
if (isFunction(post)) {
callback = post;
post = null;
}
var xhr = new this.XHR(),
self = this;
xhr.open(method, url, true);
this.outstandingRequests.count ++;
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
try {
callback(xhr.status || 200, xhr.responseText);
} finally {
self.outstandingRequests.count--;
self.processRequestCallbacks();
}
}
};
xhr.send(post || '');
},
processRequestCallbacks: function(){
if (this.outstandingRequests.count === 0) {
while(this.outstandingRequests.callbacks.length) {
try {
this.outstandingRequests.callbacks.pop()();
} catch (e) {
}
}
}
},
notifyWhenNoOutstandingRequests: function(callback){
if (this.outstandingRequests.count === 0) {
callback();
} else {
this.outstandingRequests.callbacks.push(callback);
}
},
watchUrl: function(fn){
this.urlListeners.push(fn);
},
startUrlWatcher: function() {
var self = this;
(function pull () {
if (self.expectedUrl !== self.location.href) {
foreach(self.urlListeners, function(listener){
try {
listener(self.location.href);
} catch (e) {
error(e);
}
});
self.expectedUrl = self.location.href;
}
self.setTimeout(pull, self.delay);
})();
},
setUrl: function(url) {
var existingURL = this.location.href;
if (!existingURL.match(/#/)) existingURL += '#';
if (!url.match(/#/)) url += '#';
if (existingURL != url) {
this.location.href = this.expectedUrl = url;
}
},
getUrl: function() {
return this.location.href;
}
};

212
src/Compiler.js Normal file
View file

@ -0,0 +1,212 @@
/**
* Template provides directions an how to bind to a given element.
* It contains a list of init functions which need to be called to
* bind to a new instance of elements. It also provides a list
* of child paths which contain child templates
*/
function Template(priority) {
this.paths = [];
this.children = [];
this.inits = [];
this.priority = priority || 0;
}
Template.prototype = {
init: function(element, scope) {
var inits = {};
this.collectInits(element, inits);
foreachSorted(inits, function(queue){
foreach(queue, function(fn){
fn(scope);
});
});
},
collectInits: function(element, inits) {
var queue = inits[this.priority];
if (!queue) {
inits[this.priority] = queue = [];
}
element = jqLite(element);
foreach(this.inits, function(fn) {
queue.push(function(scope) {
scope.$tryEval(fn, element, element);
});
});
var i,
childNodes = element[0].childNodes,
children = this.children,
paths = this.paths,
length = paths.length;
for (i = 0; i < length; i++) {
children[i].collectInits(childNodes[paths[i]], inits);
}
},
addInit:function(init) {
if (init) {
this.inits.push(init);
}
},
addChild: function(index, template) {
if (template) {
this.paths.push(index);
this.children.push(template);
}
},
empty: function() {
return this.inits.length === 0 && this.paths.length === 0;
}
};
///////////////////////////////////
//Compiler
//////////////////////////////////
function Compiler(textMarkup, attrMarkup, directives, widgets){
this.textMarkup = textMarkup;
this.attrMarkup = attrMarkup;
this.directives = directives;
this.widgets = widgets;
}
Compiler.prototype = {
compile: function(rawElement) {
rawElement = jqLite(rawElement);
var index = 0,
template,
parent = rawElement.parent();
if (parent && parent[0]) {
parent = parent[0];
for(var i = 0; i < parent.childNodes.length; i++) {
if (parent.childNodes[i] == rawElement[0]) {
index = i;
}
}
}
template = this.templatize(rawElement, index, 0) || new Template();
return function(element, parentScope){
element = jqLite(element);
var scope = parentScope && parentScope.$eval ?
parentScope :
createScope(parentScope || {}, angularService);
return extend(scope, {
$element:element,
$init: function() {
template.init(element, scope);
scope.$eval();
delete scope.$init;
return scope;
}
});
};
},
templatize: function(element, elementIndex, priority){
var self = this,
widget,
directiveFns = self.directives,
descend = true,
directives = true,
template,
selfApi = {
compile: bind(self, self.compile),
comment:function(text) {return jqLite(document.createComment(text));},
element:function(type) {return jqLite(document.createElement(type));},
text:function(text) {return jqLite(document.createTextNode(text));},
descend: function(value){ if(isDefined(value)) descend = value; return descend;},
directives: function(value){ if(isDefined(value)) directives = value; return directives;}
};
priority = element.attr('ng-eval-order') || priority || 0;
if (isString(priority)) {
priority = PRIORITY[uppercase(priority)] || 0;
}
template = new Template(priority);
eachAttribute(element, function(value, name){
if (!widget) {
if (widget = self.widgets['@' + name]) {
widget = bind(selfApi, widget, value, element);
}
}
});
if (!widget) {
if (widget = self.widgets[nodeName(element)]) {
widget = bind(selfApi, widget, element);
}
}
if (widget) {
descend = false;
directives = false;
var parent = element.parent();
template.addInit(widget.call(selfApi, element));
if (parent && parent[0]) {
element = jqLite(parent[0].childNodes[elementIndex]);
}
}
if (descend){
// process markup for text nodes only
eachTextNode(element, function(textNode){
var text = textNode.text();
foreach(self.textMarkup, function(markup){
markup.call(selfApi, text, textNode, element);
});
});
}
if (directives) {
// Process attributes/directives
eachAttribute(element, function(value, name){
foreach(self.attrMarkup, function(markup){
markup.call(selfApi, value, name, element);
});
});
eachAttribute(element, function(value, name){
template.addInit((directiveFns[name]||noop).call(selfApi, value, element));
});
}
// Process non text child nodes
if (descend) {
eachNode(element, function(child, i){
template.addChild(i, self.templatize(child, i, priority));
});
}
return template.empty() ? null : template;
}
};
function eachTextNode(element, fn){
var i, chldNodes = element[0].childNodes || [], chld;
for (i = 0; i < chldNodes.length; i++) {
if(isTextNode(chld = chldNodes[i])) {
fn(jqLite(chld), i);
}
}
}
function eachNode(element, fn){
var i, chldNodes = element[0].childNodes || [], chld;
for (i = 0; i < chldNodes.length; i++) {
if(!isTextNode(chld = chldNodes[i])) {
fn(jqLite(chld), i);
}
}
}
function eachAttribute(element, fn){
var i, attrs = element[0].attributes || [], chld, attr, name, value, attrValue = {};
for (i = 0; i < attrs.length; i++) {
attr = attrs[i];
name = attr.name.replace(':', '-');
value = attr.value;
if (msie && name == 'href') {
value = decodeURIComponent(element[0].getAttribute(name, 2));
}
attrValue[name] = value;
}
foreachSorted(attrValue, fn);
}

105
src/JSON.js Normal file
View file

@ -0,0 +1,105 @@
array = [].constructor;
function toJson(obj, pretty){
var buf = [];
toJsonArray(buf, obj, pretty ? "\n " : null, []);
return buf.join('');
}
function toPrettyJson(obj) {
return toJson(obj, true);
}
function fromJson(json) {
if (!json) return json;
try {
var parser = new Parser(json, true);
var expression = parser.primary();
parser.assertAllConsumed();
return expression();
} catch (e) {
error("fromJson error: ", json, e);
throw e;
}
}
angular['toJson'] = toJson;
angular['fromJson'] = fromJson;
function toJsonArray(buf, obj, pretty, stack){
if (typeof obj == "object") {
if (includes(stack, obj)) {
buf.push("RECURSION");
return;
}
stack.push(obj);
}
var type = typeof obj;
if (obj === null) {
buf.push("null");
} else if (type === 'function') {
return;
} else if (type === 'boolean') {
buf.push('' + obj);
} else if (type === 'number') {
if (isNaN(obj)) {
buf.push('null');
} else {
buf.push('' + obj);
}
} else if (type === 'string') {
return buf.push(angular['String']['quoteUnicode'](obj));
} else if (type === 'object') {
if (obj instanceof Array) {
buf.push("[");
var len = obj.length;
var sep = false;
for(var i=0; i<len; i++) {
var item = obj[i];
if (sep) buf.push(",");
if (typeof item == 'function' || typeof item == 'undefined') {
buf.push("null");
} else {
toJsonArray(buf, item, pretty, stack);
}
sep = true;
}
buf.push("]");
} else if (obj instanceof Date) {
buf.push(angular['String']['quoteUnicode'](angular['Date']['toString'](obj)));
} else {
buf.push("{");
if (pretty) buf.push(pretty);
var comma = false;
var childPretty = pretty ? pretty + " " : false;
var keys = [];
for(var k in obj) {
if (k.indexOf('$$') === 0 || obj[k] === undefined)
continue;
keys.push(k);
}
keys.sort();
for ( var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
var key = keys[keyIndex];
try {
var value = obj[key];
if (typeof value != 'function') {
if (comma) {
buf.push(",");
if (pretty) buf.push(pretty);
}
buf.push(angular['String']['quote'](key));
buf.push(":");
toJsonArray(buf, value, childPretty, stack);
comma = true;
}
} catch (e) {
}
}
buf.push("}");
}
}
if (typeof obj == "object") {
stack.pop();
}
}

730
src/Parser.js Normal file
View file

@ -0,0 +1,730 @@
function Lexer(text, parsStrings){
this.text = text;
// UTC dates have 20 characters, we send them through parser
this.dateParseLength = parsStrings ? 20 : -1;
this.tokens = [];
this.index = 0;
}
Lexer.OPERATORS = {
'null':function(self){return null;},
'true':function(self){return true;},
'false':function(self){return false;},
'undefined':noop,
'+':function(self, a,b){return (isDefined(a)?a:0)+(isDefined(b)?b:0);},
'-':function(self, a,b){return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
'*':function(self, a,b){return a*b;},
'/':function(self, a,b){return a/b;},
'%':function(self, a,b){return a%b;},
'^':function(self, a,b){return a^b;},
'=':function(self, a,b){return setter(self, a, b);},
'==':function(self, a,b){return a==b;},
'!=':function(self, a,b){return a!=b;},
'<':function(self, a,b){return a<b;},
'>':function(self, a,b){return a>b;},
'<=':function(self, a,b){return a<=b;},
'>=':function(self, a,b){return a>=b;},
'&&':function(self, a,b){return a&&b;},
'||':function(self, a,b){return a||b;},
'&':function(self, a,b){return a&b;},
// '|':function(self, a,b){return a|b;},
'|':function(self, a,b){return b(self, a);},
'!':function(self, a){return !a;}
};
Lexer.ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
Lexer.prototype = {
peek: function() {
if (this.index + 1 < this.text.length) {
return this.text.charAt(this.index + 1);
} else {
return false;
}
},
parse: function() {
var tokens = this.tokens;
var OPERATORS = Lexer.OPERATORS;
var canStartRegExp = true;
while (this.index < this.text.length) {
var ch = this.text.charAt(this.index);
if (ch == '"' || ch == "'") {
this.readString(ch);
canStartRegExp = true;
} else if (ch == '(' || ch == '[') {
tokens.push({index:this.index, text:ch});
this.index++;
} else if (ch == '{' ) {
var peekCh = this.peek();
if (peekCh == ':' || peekCh == '(') {
tokens.push({index:this.index, text:ch + peekCh});
this.index++;
} else {
tokens.push({index:this.index, text:ch});
}
this.index++;
canStartRegExp = true;
} else if (ch == ')' || ch == ']' || ch == '}' ) {
tokens.push({index:this.index, text:ch});
this.index++;
canStartRegExp = false;
} else if ( ch == ':' || ch == '.' || ch == ',' || ch == ';') {
tokens.push({index:this.index, text:ch});
this.index++;
canStartRegExp = true;
} else if ( canStartRegExp && ch == '/' ) {
this.readRegexp();
canStartRegExp = false;
} else if ( this.isNumber(ch) ) {
this.readNumber();
canStartRegExp = false;
} else if (this.isIdent(ch)) {
this.readIdent();
canStartRegExp = false;
} else if (this.isWhitespace(ch)) {
this.index++;
} else {
var ch2 = ch + this.peek();
var fn = OPERATORS[ch];
var fn2 = OPERATORS[ch2];
if (fn2) {
tokens.push({index:this.index, text:ch2, fn:fn2});
this.index += 2;
} else if (fn) {
tokens.push({index:this.index, text:ch, fn:fn});
this.index += 1;
} else {
throw "Lexer Error: Unexpected next character [" +
this.text.substring(this.index) +
"] in expression '" + this.text +
"' at column '" + (this.index+1) + "'.";
}
canStartRegExp = true;
}
}
return tokens;
},
isNumber: function(ch) {
return '0' <= ch && ch <= '9';
},
isWhitespace: function(ch) {
return ch == ' ' || ch == '\r' || ch == '\t' ||
ch == '\n' || ch == '\v';
},
isIdent: function(ch) {
return 'a' <= ch && ch <= 'z' ||
'A' <= ch && ch <= 'Z' ||
'_' == ch || ch == '$';
},
readNumber: function() {
var number = "";
var start = this.index;
while (this.index < this.text.length) {
var ch = this.text.charAt(this.index);
if (ch == '.' || this.isNumber(ch)) {
number += ch;
} else {
break;
}
this.index++;
}
number = 1 * number;
this.tokens.push({index:start, text:number,
fn:function(){return number;}});
},
readIdent: function() {
var ident = "";
var start = this.index;
while (this.index < this.text.length) {
var ch = this.text.charAt(this.index);
if (ch == '.' || this.isIdent(ch) || this.isNumber(ch)) {
ident += ch;
} else {
break;
}
this.index++;
}
var fn = Lexer.OPERATORS[ident];
if (!fn) {
fn = getterFn(ident);
fn.isAssignable = ident;
}
this.tokens.push({index:start, text:ident, fn:fn});
},
readString: function(quote) {
var start = this.index;
var dateParseLength = this.dateParseLength;
this.index++;
var string = "";
var rawString = quote;
var escape = false;
while (this.index < this.text.length) {
var ch = this.text.charAt(this.index);
rawString += ch;
if (escape) {
if (ch == 'u') {
var hex = this.text.substring(this.index + 1, this.index + 5);
this.index += 4;
string += String.fromCharCode(parseInt(hex, 16));
} else {
var rep = Lexer.ESCAPE[ch];
if (rep) {
string += rep;
} else {
string += ch;
}
}
escape = false;
} else if (ch == '\\') {
escape = true;
} else if (ch == quote) {
this.index++;
this.tokens.push({index:start, text:rawString, string:string,
fn:function(){
return (string.length == dateParseLength) ?
angular['String']['toDate'](string) : string;
}});
return;
} else {
string += ch;
}
this.index++;
}
throw "Lexer Error: Unterminated quote [" +
this.text.substring(start) + "] starting at column '" +
(start+1) + "' in expression '" + this.text + "'.";
},
readRegexp: function(quote) {
var start = this.index;
this.index++;
var regexp = "";
var escape = false;
while (this.index < this.text.length) {
var ch = this.text.charAt(this.index);
if (escape) {
regexp += ch;
escape = false;
} else if (ch === '\\') {
regexp += ch;
escape = true;
} else if (ch === '/') {
this.index++;
var flags = "";
if (this.isIdent(this.text.charAt(this.index))) {
this.readIdent();
flags = this.tokens.pop().text;
}
var compiledRegexp = new RegExp(regexp, flags);
this.tokens.push({index:start, text:regexp, flags:flags,
fn:function(){return compiledRegexp;}});
return;
} else {
regexp += ch;
}
this.index++;
}
throw "Lexer Error: Unterminated RegExp [" +
this.text.substring(start) + "] starting at column '" +
(start+1) + "' in expression '" + this.text + "'.";
}
};
/////////////////////////////////////////
function Parser(text, parseStrings){
this.text = text;
this.tokens = new Lexer(text, parseStrings).parse();
this.index = 0;
}
Parser.ZERO = function(){
return 0;
};
Parser.prototype = {
error: function(msg, token) {
throw "Token '" + token.text +
"' is " + msg + " at column='" +
(token.index + 1) + "' of expression '" +
this.text + "' starting at '" + this.text.substring(token.index) + "'.";
},
peekToken: function() {
if (this.tokens.length === 0)
throw "Unexpected end of expression: " + this.text;
return this.tokens[0];
},
peek: function(e1, e2, e3, e4) {
var tokens = this.tokens;
if (tokens.length > 0) {
var token = tokens[0];
var t = token.text;
if (t==e1 || t==e2 || t==e3 || t==e4 ||
(!e1 && !e2 && !e3 && !e4)) {
return token;
}
}
return false;
},
expect: function(e1, e2, e3, e4){
var token = this.peek(e1, e2, e3, e4);
if (token) {
this.tokens.shift();
this.currentToken = token;
return token;
}
return false;
},
consume: function(e1){
if (!this.expect(e1)) {
var token = this.peek();
throw "Expecting '" + e1 + "' at column '" +
(token.index+1) + "' in '" +
this.text + "' got '" +
this.text.substring(token.index) + "'.";
}
},
_unary: function(fn, right) {
return function(self) {
return fn(self, right(self));
};
},
_binary: function(left, fn, right) {
return function(self) {
return fn(self, left(self), right(self));
};
},
hasTokens: function () {
return this.tokens.length > 0;
},
assertAllConsumed: function(){
if (this.tokens.length !== 0) {
throw "Did not understand '" + this.text.substring(this.tokens[0].index) +
"' while evaluating '" + this.text + "'.";
}
},
statements: function(){
var statements = [];
while(true) {
if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
statements.push(this.filterChain());
if (!this.expect(';')) {
return function (self){
var value;
for ( var i = 0; i < statements.length; i++) {
var statement = statements[i];
if (statement)
value = statement(self);
}
return value;
};
}
}
},
filterChain: function(){
var left = this.expression();
var token;
while(true) {
if ((token = this.expect('|'))) {
left = this._binary(left, token.fn, this.filter());
} else {
return left;
}
}
},
filter: function(){
return this._pipeFunction(angularFilter);
},
validator: function(){
return this._pipeFunction(angularValidator);
},
_pipeFunction: function(fnScope){
var fn = this.functionIdent(fnScope);
var argsFn = [];
var token;
while(true) {
if ((token = this.expect(':'))) {
argsFn.push(this.expression());
} else {
var fnInvoke = function(self, input){
var args = [input];
for ( var i = 0; i < argsFn.length; i++) {
args.push(argsFn[i](self));
}
return fn.apply(self, args);
};
return function(){
return fnInvoke;
};
}
}
},
expression: function(){
return this.throwStmt();
},
throwStmt: function(){
if (this.expect('throw')) {
var throwExp = this.assignment();
return function (self) {
throw throwExp(self);
};
} else {
return this.assignment();
}
},
assignment: function(){
var left = this.logicalOR();
var token;
if (token = this.expect('=')) {
if (!left.isAssignable) {
throw "Left hand side '" +
this.text.substring(0, token.index) + "' of assignment '" +
this.text.substring(token.index) + "' is not assignable.";
}
var ident = function(){return left.isAssignable;};
return this._binary(ident, token.fn, this.logicalOR());
} else {
return left;
}
},
logicalOR: function(){
var left = this.logicalAND();
var token;
while(true) {
if ((token = this.expect('||'))) {
left = this._binary(left, token.fn, this.logicalAND());
} else {
return left;
}
}
},
logicalAND: function(){
var left = this.equality();
var token;
if ((token = this.expect('&&'))) {
left = this._binary(left, token.fn, this.logicalAND());
}
return left;
},
equality: function(){
var left = this.relational();
var token;
if ((token = this.expect('==','!='))) {
left = this._binary(left, token.fn, this.equality());
}
return left;
},
relational: function(){
var left = this.additive();
var token;
if (token = this.expect('<', '>', '<=', '>=')) {
left = this._binary(left, token.fn, this.relational());
}
return left;
},
additive: function(){
var left = this.multiplicative();
var token;
while(token = this.expect('+','-')) {
left = this._binary(left, token.fn, this.multiplicative());
}
return left;
},
multiplicative: function(){
var left = this.unary();
var token;
while(token = this.expect('*','/','%')) {
left = this._binary(left, token.fn, this.unary());
}
return left;
},
unary: function(){
var token;
if (this.expect('+')) {
return this.primary();
} else if (token = this.expect('-')) {
return this._binary(Parser.ZERO, token.fn, this.unary());
} else if (token = this.expect('!')) {
return this._unary(token.fn, this.unary());
} else {
return this.primary();
}
},
functionIdent: function(fnScope) {
var token = this.expect();
var element = token.text.split('.');
var instance = fnScope;
var key;
for ( var i = 0; i < element.length; i++) {
key = element[i];
if (instance)
instance = instance[key];
}
if (typeof instance != 'function') {
throw "Function '" + token.text + "' at column '" +
(token.index+1) + "' in '" + this.text + "' is not defined.";
}
return instance;
},
primary: function() {
var primary;
if (this.expect('(')) {
var expression = this.filterChain();
this.consume(')');
primary = expression;
} else if (this.expect('[')) {
primary = this.arrayDeclaration();
} else if (this.expect('{')) {
primary = this.object();
} else if (this.expect('{:')) {
primary = this.closure(false);
} else if (this.expect('{(')) {
primary = this.closure(true);
} else {
var token = this.expect();
primary = token.fn;
if (!primary) {
this.error("not a primary expression", token);
}
}
var next;
while (next = this.expect('(', '[', '.')) {
if (next.text === '(') {
primary = this.functionCall(primary);
} else if (next.text === '[') {
primary = this.objectIndex(primary);
} else if (next.text === '.') {
primary = this.fieldAccess(primary);
} else {
throw "IMPOSSIBLE";
}
}
return primary;
},
closure: function(hasArgs) {
var args = [];
if (hasArgs) {
if (!this.expect(')')) {
args.push(this.expect().text);
while(this.expect(',')) {
args.push(this.expect().text);
}
this.consume(')');
}
this.consume(":");
}
var statements = this.statements();
this.consume("}");
return function(self) {
return function($){
var scope = createScope(self);
scope['$'] = $;
for ( var i = 0; i < args.length; i++) {
setter(scope, args[i], arguments[i]);
}
return statements(scope);
};
};
},
fieldAccess: function(object) {
var field = this.expect().text;
var getter = getterFn(field);
var fn = function (self){
return getter(object(self));
};
fn.isAssignable = field;
return fn;
},
objectIndex: function(obj) {
var indexFn = this.expression();
this.consume(']');
if (this.expect('=')) {
var rhs = this.expression();
return function (self){
return obj(self)[indexFn(self)] = rhs(self);
};
} else {
return function (self){
var o = obj(self);
var i = indexFn(self);
return (o) ? o[i] : undefined;
};
}
},
functionCall: function(fn) {
var argsFn = [];
if (this.peekToken().text != ')') {
do {
argsFn.push(this.expression());
} while (this.expect(','));
}
this.consume(')');
return function (self){
var args = [];
for ( var i = 0; i < argsFn.length; i++) {
args.push(argsFn[i](self));
}
var fnPtr = fn(self);
if (typeof fnPtr === 'function') {
return fnPtr.apply(self, args);
} else {
throw "Expression '" + fn.isAssignable + "' is not a function.";
}
};
},
// This is used with json array declaration
arrayDeclaration: function () {
var elementFns = [];
if (this.peekToken().text != ']') {
do {
elementFns.push(this.expression());
} while (this.expect(','));
}
this.consume(']');
return function (self){
var array = [];
for ( var i = 0; i < elementFns.length; i++) {
array.push(elementFns[i](self));
}
return array;
};
},
object: function () {
var keyValues = [];
if (this.peekToken().text != '}') {
do {
var token = this.expect(),
key = token.string || token.text;
this.consume(":");
var value = this.expression();
keyValues.push({key:key, value:value});
} while (this.expect(','));
}
this.consume('}');
return function (self){
var object = {};
for ( var i = 0; i < keyValues.length; i++) {
var keyValue = keyValues[i];
var value = keyValue.value(self);
object[keyValue.key] = value;
}
return object;
};
},
entityDeclaration: function () {
var decl = [];
while(this.hasTokens()) {
decl.push(this.entityDecl());
if (!this.expect(';')) {
this.assertAllConsumed();
}
}
return function (self){
var code = "";
for ( var i = 0; i < decl.length; i++) {
code += decl[i](self);
}
return code;
};
},
entityDecl: function () {
var entity = this.expect().text;
var instance;
var defaults;
if (this.expect('=')) {
instance = entity;
entity = this.expect().text;
}
if (this.expect(':')) {
defaults = this.primary()(null);
}
return function(self) {
var Entity = self.datastore.entity(entity, defaults);
setter(self, entity, Entity);
if (instance) {
var document = Entity();
document['$$anchor'] = instance;
setter(self, instance, document);
return "$anchor." + instance + ":{" +
instance + "=" + entity + ".load($anchor." + instance + ");" +
instance + ".$$anchor=" + angular['String']['quote'](instance) + ";" +
"};";
} else {
return "";
}
};
},
watch: function () {
var decl = [];
while(this.hasTokens()) {
decl.push(this.watchDecl());
if (!this.expect(';')) {
this.assertAllConsumed();
}
}
this.assertAllConsumed();
return function (self){
for ( var i = 0; i < decl.length; i++) {
var d = decl[i](self);
self.addListener(d.name, d.fn);
}
};
},
watchDecl: function () {
var anchorName = this.expect().text;
this.consume(":");
var expression;
if (this.peekToken().text == '{') {
this.consume("{");
expression = this.statements();
this.consume("}");
} else {
expression = this.expression();
}
return function(self) {
return {name:anchorName, fn:expression};
};
}
};

140
src/Resource.js Normal file
View file

@ -0,0 +1,140 @@
function Route(template, defaults) {
this.template = template = template + '#';
this.defaults = defaults || {};
var urlParams = this.urlParams = {};
foreach(template.split(/\W/), function(param){
if (param && template.match(new RegExp(":" + param + "\\W"))) {
urlParams[param] = true;
}
});
}
Route.prototype = {
url: function(params) {
var path = [];
var self = this;
var url = this.template;
params = params || {};
foreach(this.urlParams, function(_, urlParam){
var value = params[urlParam] || self.defaults[urlParam] || "";
url = url.replace(new RegExp(":" + urlParam + "(\\W)"), value + "$1");
});
url = url.replace(/\/?#$/, '');
var query = [];
foreachSorted(params, function(value, key){
if (!self.urlParams[key]) {
query.push(encodeURI(key) + '=' + encodeURI(value));
}
});
return url + (query.length ? '?' + query.join('&') : '');
}
};
function ResourceFactory(xhr) {
this.xhr = xhr;
}
ResourceFactory.DEFAULT_ACTIONS = {
'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'}
};
ResourceFactory.prototype = {
route: function(url, paramDefaults, actions){
var self = this;
var route = new Route(url);
actions = extend({}, ResourceFactory.DEFAULT_ACTIONS, actions);
function extractParams(data){
var ids = {};
foreach(paramDefaults || {}, function(value, key){
ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
});
return ids;
}
function Resource(value){
copy(value || {}, this);
}
foreach(actions, function(action, name){
var isGet = action.method == 'GET';
var isPost = action.method == 'POST';
Resource[name] = function (a1, a2, a3) {
var params = {};
var data;
var callback = noop;
switch(arguments.length) {
case 3: callback = a3;
case 2:
if (isFunction(a2)) {
callback = a2;
} else {
params = a1;
data = a2;
break;
}
case 1:
if (isFunction(a1)) callback = a1;
else if (isPost) data = a1;
else params = a1;
break;
case 0: break;
default:
throw "Expected between 0-3 arguments [params, data, callback], got " + arguments.length + " arguments.";
}
var value = action.isArray ? [] : new Resource(data;)
self.xhr(
action.method,
route.url(extend({}, action.params || {}, extractParams(data), params)),
data,
function(status, response, clear) {
if (status == 200) {
if (action.isArray) {
if (action.cacheThenRetrieve)
value = [];
foreach(response, function(item){
value.push(new Resource(item));
});
} else {
copy(response, value);
}
(callback||noop)(value);
} else {
throw {status: status, response:response, message: status + ": " + response};
}
},
action.cacheThenRetrieve
);
return value;
};
Resource.bind = function(additionalParamDefaults){
return self.route(url, extend({}, paramDefaults, additionalParamDefaults), actions);
};
if (!isGet) {
Resource.prototype['$' + name] = function(a1, a2){
var params = {};
var callback = noop;
switch(arguments.length) {
case 2: params = a1; callback = a2;
case 1: if (typeof a1 == 'function') callback = a1; else params = a1;
case 0: break;
default:
throw "Expected between 1-2 arguments [params, callback], got " + arguments.length + " arguments.";
}
var self = this;
Resource[name](params, this, function(response){
copy(response, self);
callback(self);
});
};
}
});
return Resource;
}
};

224
src/Scope.js Normal file
View file

@ -0,0 +1,224 @@
function getter(instance, path, unboundFn) {
if (!path) return instance;
var element = path.split('.');
var key;
var lastInstance = instance;
var len = element.length;
for ( var i = 0; i < len; i++) {
key = element[i];
if (!key.match(/^[\$\w][\$\w\d]*$/))
throw "Expression '" + path + "' is not a valid expression for accesing variables.";
if (instance) {
lastInstance = instance;
instance = instance[key];
}
if (isUndefined(instance) && key.charAt(0) == '$') {
var type = angular['Global']['typeOf'](lastInstance);
type = angular[type.charAt(0).toUpperCase()+type.substring(1)];
var fn = type ? type[[key.substring(1)]] : undefined;
if (fn) {
instance = bind(lastInstance, fn, lastInstance);
return instance;
}
}
}
if (!unboundFn && isFunction(instance) && !instance['$$factory']) {
return bind(lastInstance, instance);
}
return instance;
}
function setter(instance, path, value){
var element = path.split('.');
for ( var i = 0; element.length > 1; i++) {
var key = element.shift();
var newInstance = instance[key];
if (!newInstance) {
newInstance = {};
instance[key] = newInstance;
}
instance = newInstance;
}
instance[element.shift()] = value;
return value;
}
///////////////////////////////////
var getterFnCache = {};
function getterFn(path){
var fn = getterFnCache[path];
if (fn) return fn;
var code = 'function (self){\n';
code += ' var last, fn, type;\n';
foreach(path.split('.'), function(key) {
key = (key == 'this') ? '["this"]' : '.' + key;
code += ' if(!self) return self;\n';
code += ' last = self;\n';
code += ' self = self' + key + ';\n';
code += ' if(typeof self == "function") \n';
code += ' self = function(){ return last'+key+'.apply(last, arguments); };\n';
if (key.charAt(1) == '$') {
// special code for super-imposed functions
var name = key.substr(2);
code += ' if(!self) {\n';
code += ' type = angular.Global.typeOf(last);\n';
code += ' fn = (angular[type.charAt(0).toUpperCase() + type.substring(1)]||{})["' + name + '"];\n';
code += ' if (fn)\n';
code += ' self = function(){ return fn.apply(last, [last].concat(slice.call(arguments, 0, arguments.length))); };\n';
code += ' }\n';
}
});
code += ' return self;\n}';
fn = eval('(' + code + ')');
fn.toString = function(){ return code; };
return getterFnCache[path] = fn;
}
///////////////////////////////////
var compileCache = {};
function expressionCompile(exp){
if (isFunction(exp)) return exp;
var fn = compileCache[exp];
if (!fn) {
var parser = new Parser(exp);
var fnSelf = parser.statements();
parser.assertAllConsumed();
fn = compileCache[exp] = extend(
function(){ return fnSelf(this);},
{fnSelf: fnSelf});
}
return fn;
}
function rethrow(e) { throw e; }
function errorHandlerFor(element, error) {
elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error);
}
var scopeId = 0;
function createScope(parent, services, existing) {
function Parent(){}
function API(){}
function Behavior(){}
var instance, behavior, api, evalLists = {sorted:[]}, servicesCache = extend({}, existing);
parent = Parent.prototype = (parent || {});
api = API.prototype = new Parent();
behavior = Behavior.prototype = new API();
instance = new Behavior();
extend(api, {
'this': instance,
$id: (scopeId++),
$parent: parent,
$bind: bind(instance, bind, instance),
$get: bind(instance, getter, instance),
$set: bind(instance, setter, instance),
$eval: function $eval(exp) {
if (exp !== undefined) {
return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length));
} else {
for ( var i = 0, iSize = evalLists.sorted.length; i < iSize; i++) {
for ( var queue = evalLists.sorted[i],
jSize = queue.length,
j= 0; j < jSize; j++) {
instance.$tryEval(queue[j].fn, queue[j].handler);
}
}
}
},
$tryEval: function (expression, exceptionHandler) {
try {
return expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length));
} catch (e) {
error(e);
if (isFunction(exceptionHandler)) {
exceptionHandler(e);
} else if (exceptionHandler) {
errorHandlerFor(exceptionHandler, e);
} else if (isFunction(instance.$exceptionHandler)) {
instance.$exceptionHandler(e);
}
}
},
$watch: function(watchExp, listener, exceptionHandler) {
var watch = expressionCompile(watchExp),
last;
function watcher(){
var value = watch.call(instance),
lastValue = last;
if (last !== value) {
last = value;
instance.$tryEval(listener, exceptionHandler, value, lastValue);
}
}
instance.$onEval(PRIORITY_WATCH, watcher);
watcher();
},
$onEval: function(priority, expr, exceptionHandler){
if (!isNumber(priority)) {
exceptionHandler = expr;
expr = priority;
priority = 0;
}
var evalList = evalLists[priority];
if (!evalList) {
evalList = evalLists[priority] = [];
evalList.priority = priority;
evalLists.sorted.push(evalList);
evalLists.sorted.sort(function(a,b){return a.priority-b.priority;});
}
evalList.push({
fn: expressionCompile(expr),
handler: exceptionHandler
});
},
$become: function(Class) {
// remove existing
foreach(behavior, function(value, key){ delete behavior[key]; });
foreach((Class || noop).prototype, function(fn, name){
behavior[name] = bind(instance, fn);
});
(Class || noop).call(instance);
}
});
if (!parent.$root) {
api.$root = instance;
api.$parent = instance;
}
function inject(name){
var service = servicesCache[name], factory, args = [];
if (isUndefined(service)) {
factory = services[name];
if (!isFunction(factory))
throw "Don't know how to inject '" + name + "'.";
foreach(factory.inject, function(dependency){
args.push(inject(dependency));
});
servicesCache[name] = service = factory.apply(instance, args);
}
return service;
}
foreach(services, function(_, name){
var service = inject(name);
if (service) {
setter(instance, name, service);
}
});
return instance;
}

70
src/angular-bootstrap.js vendored Normal file
View file

@ -0,0 +1,70 @@
/**
* The MIT License
*
* Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
(function(previousOnLoad){
var filename = /(.*)\/angular-(.*).js(#(.*))?/,
scripts = document.getElementsByTagName("SCRIPT"),
serverPath,
config,
match;
for(var j = 0; j < scripts.length; j++) {
match = (scripts[j].src || "").match(filename);
if (match) {
serverPath = match[1];
config = match[4];
}
}
function addScript(file){
document.write('<script type="text/javascript" src="' + serverPath + file +'"></script>');
}
addScript("/Angular.js");
addScript("/JSON.js");
addScript("/Compiler.js");
addScript("/Scope.js");
addScript("/jqLite.js");
addScript("/Parser.js");
addScript("/Resource.js");
addScript("/Browser.js");
addScript("/AngularPublic.js");
// Extension points
addScript("/services.js");
addScript("/apis.js");
addScript("/filters.js");
addScript("/formatters.js");
addScript("/validators.js");
addScript("/directives.js");
addScript("/markups.js");
addScript("/widgets.js");
window.onload = function(){
try {
if (previousOnLoad) previousOnLoad();
} catch(e) {}
angularInit(parseKeyValue(config));
};
})(window.onload);

24
src/angular.prefix Normal file
View file

@ -0,0 +1,24 @@
/**
* The MIT License
*
* Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
(function(window, document, previousOnLoad){

9
src/angular.suffix Normal file
View file

@ -0,0 +1,9 @@
window.onload = function(){
try {
if (previousOnLoad) previousOnLoad();
} catch(e) {}
angularInit(parseKeyValue(angularJsConfig(document)));
};
})(window, document, window.onload);

338
src/apis.js Normal file
View file

@ -0,0 +1,338 @@
var angularGlobal = {
'typeOf':function(obj){
if (obj === null) return "null";
var type = typeof obj;
if (type == "object") {
if (obj instanceof Array) return "array";
if (obj instanceof Date) return "date";
if (obj.nodeType == 1) return "element";
}
return type;
}
};
var angularCollection = {
'size': size
};
var angularObject = {
'extend': extend
};
var angularArray = {
'indexOf': indexOf,
'include': includes,
'includeIf':function(array, value, condition) {
var index = indexOf(array, value);
if (condition) {
if (index == -1)
array.push(value);
} else {
array.splice(index, 1);
}
return array;
},
'sum':function(array, expression) {
var fn = angular['Function']['compile'](expression);
var sum = 0;
for (var i = 0; i < array.length; i++) {
var value = 1 * fn(array[i]);
if (!isNaN(value)){
sum += value;
}
}
return sum;
},
'remove':function(array, value) {
var index = indexOf(array, value);
if (index >=0)
array.splice(index, 1);
return value;
},
'find':function(array, condition, defaultValue) {
if (!condition) return undefined;
var fn = angular['Function']['compile'](condition);
foreach(array, function($){
if (fn($)){
defaultValue = $;
return true;
}
});
return defaultValue;
},
'findById':function(array, id) {
return angular.Array.find(array, function($){return $.$id == id;}, null);
},
'filter':function(array, expression) {
var predicates = [];
predicates.check = function(value) {
for (var j = 0; j < predicates.length; j++) {
if(!predicates[j](value)) {
return false;
}
}
return true;
};
var search = function(obj, text){
if (text.charAt(0) === '!') {
return !search(obj, text.substr(1));
}
switch (typeof obj) {
case "boolean":
case "number":
case "string":
return ('' + obj).toLowerCase().indexOf(text) > -1;
case "object":
for ( var objKey in obj) {
if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
return true;
}
}
return false;
case "array":
for ( var i = 0; i < obj.length; i++) {
if (search(obj[i], text)) {
return true;
}
}
return false;
default:
return false;
}
};
switch (typeof expression) {
case "boolean":
case "number":
case "string":
expression = {$:expression};
case "object":
for (var key in expression) {
if (key == '$') {
(function(){
var text = (''+expression[key]).toLowerCase();
if (!text) return;
predicates.push(function(value) {
return search(value, text);
});
})();
} else {
(function(){
var path = key;
var text = (''+expression[key]).toLowerCase();
if (!text) return;
predicates.push(function(value) {
return search(getter(value, path), text);
});
})();
}
}
break;
case "function":
predicates.push(expression);
break;
default:
return array;
}
var filtered = [];
for ( var j = 0; j < array.length; j++) {
var value = array[j];
if (predicates.check(value)) {
filtered.push(value);
}
}
return filtered;
},
'add':function(array, value) {
array.push(isUndefined(value)? {} : value);
return array;
},
'count':function(array, condition) {
if (!condition) return array.length;
var fn = angular['Function']['compile'](condition), count = 0;
foreach(array, function(value){
if (fn(value)) {
count ++;
}
});
return count;
},
'orderBy':function(array, expression, descend) {
function reverse(comp, descending) {
return toBoolean(descending) ?
function(a,b){return comp(b,a);} : comp;
}
function compare(v1, v2){
var t1 = typeof v1;
var t2 = typeof v2;
if (t1 == t2) {
if (t1 == "string") v1 = v1.toLowerCase();
if (t1 == "string") v2 = v2.toLowerCase();
if (v1 === v2) return 0;
return v1 < v2 ? -1 : 1;
} else {
return t1 < t2 ? -1 : 1;
}
}
expression = isArray(expression) ? expression: [expression];
expression = map(expression, function($){
var descending = false;
if (typeof $ == "string" && ($.charAt(0) == '+' || $.charAt(0) == '-')) {
descending = $.charAt(0) == '-';
$ = $.substring(1);
}
var get = $ ? expressionCompile($).fnSelf : identity;
return reverse(function(a,b){
return compare(get(a),get(b));
}, descending);
});
var comparator = function(o1, o2){
for ( var i = 0; i < expression.length; i++) {
var comp = expression[i](o1, o2);
if (comp !== 0) return comp;
}
return 0;
};
var arrayCopy = [];
for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
return arrayCopy.sort(reverse(comparator, descend));
},
'orderByToggle':function(predicate, attribute) {
var STRIP = /^([+|-])?(.*)/;
var ascending = false;
var index = -1;
foreach(predicate, function($, i){
if (index == -1) {
if ($ == attribute) {
ascending = true;
index = i;
return true;
}
if (($.charAt(0)=='+'||$.charAt(0)=='-') && $.substring(1) == attribute) {
ascending = $.charAt(0) == '+';
index = i;
return true;
}
}
});
if (index >= 0) {
predicate.splice(index, 1);
}
predicate.unshift((ascending ? "-" : "+") + attribute);
return predicate;
},
'orderByDirection':function(predicate, attribute, ascend, descend) {
ascend = ascend || 'ng-ascend';
descend = descend || 'ng-descend';
var att = predicate[0] || '';
var direction = true;
if (att.charAt(0) == '-') {
att = att.substring(1);
direction = false;
} else if(att.charAt(0) == '+') {
att = att.substring(1);
}
return att == attribute ? (direction ? ascend : descend) : "";
},
'merge':function(array, index, mergeValue) {
var value = array[index];
if (!value) {
value = {};
array[index] = value;
}
merge(mergeValue, value);
return array;
}
};
var angularString = {
'quote':function(string) {
return '"' + string.replace(/\\/g, '\\\\').
replace(/"/g, '\\"').
replace(/\n/g, '\\n').
replace(/\f/g, '\\f').
replace(/\r/g, '\\r').
replace(/\t/g, '\\t').
replace(/\v/g, '\\v') +
'"';
},
'quoteUnicode':function(string) {
var str = angular['String']['quote'](string);
var chars = [];
for ( var i = 0; i < str.length; i++) {
var ch = str.charCodeAt(i);
if (ch < 128) {
chars.push(str.charAt(i));
} else {
var encode = "000" + ch.toString(16);
chars.push("\\u" + encode.substring(encode.length - 4));
}
}
return chars.join('');
},
'toDate':function(string){
var match;
if (typeof string == 'string' &&
(match = string.match(/^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)Z$/))){
var date = new Date(0);
date.setUTCFullYear(match[1], match[2] - 1, match[3]);
date.setUTCHours(match[4], match[5], match[6], 0);
return date;
}
return string;
}
};
var angularDate = {
'toString':function(date){
function pad(n) { return n < 10 ? "0" + n : n; }
return !date ? date :
date.getUTCFullYear() + '-' +
pad(date.getUTCMonth() + 1) + '-' +
pad(date.getUTCDate()) + 'T' +
pad(date.getUTCHours()) + ':' +
pad(date.getUTCMinutes()) + ':' +
pad(date.getUTCSeconds()) + 'Z' ;
}
};
var angularFunction = {
'compile':function(expression) {
if (isFunction(expression)){
return expression;
} else if (expression){
return expressionCompile(expression).fnSelf;
} else {
return identity;
}
}
};
function defineApi(dst, chain, underscoreNames){
if (_) {
var lastChain = _.last(chain);
foreach(underscoreNames, function(name){
lastChain[name] = _[name];
});
}
angular[dst] = angular[dst] || {};
foreach(chain, function(parent){
extend(angular[dst], parent);
});
}
defineApi('Global', [angularGlobal],
['extend', 'clone','isEqual',
'isElement', 'isArray', 'isFunction', 'isUndefined']);
defineApi('Collection', [angularGlobal, angularCollection],
['each', 'map', 'reduce', 'reduceRight', 'detect',
'select', 'reject', 'all', 'any', 'include',
'invoke', 'pluck', 'max', 'min', 'sortBy',
'sortedIndex', 'toArray', 'size']);
defineApi('Array', [angularGlobal, angularCollection, angularArray],
['first', 'last', 'compact', 'flatten', 'without',
'uniq', 'intersect', 'zip', 'indexOf', 'lastIndexOf']);
defineApi('Object', [angularGlobal, angularCollection, angularObject],
['keys', 'values']);
defineApi('String', [angularGlobal, angularString], []);
defineApi('Date', [angularGlobal, angularDate], []);
//IE bug
angular['Date']['toString'] = angularDate['toString'];
defineApi('Function', [angularGlobal, angularCollection, angularFunction],
['bind', 'bindAll', 'delay', 'defer', 'wrap', 'compose']);

356
src/delete/Binder.js Normal file
View file

@ -0,0 +1,356 @@
function Binder(doc, widgetFactory, datastore, location, config) {
this.doc = doc;
this.location = location;
this.datastore = datastore;
this.anchor = {};
this.widgetFactory = widgetFactory;
this.config = config || {};
this.updateListeners = [];
}
Binder.parseBindings = function(string) {
var results = [];
var lastIndex = 0;
var index;
while((index = string.indexOf('{{', lastIndex)) > -1) {
if (lastIndex < index)
results.push(string.substr(lastIndex, index - lastIndex));
lastIndex = index;
index = string.indexOf('}}', index);
index = index < 0 ? string.length : index + 2;
results.push(string.substr(lastIndex, index - lastIndex));
lastIndex = index;
}
if (lastIndex != string.length)
results.push(string.substr(lastIndex, string.length - lastIndex));
return results.length === 0 ? [ string ] : results;
};
Binder.hasBinding = function(string) {
var bindings = Binder.parseBindings(string);
return bindings.length > 1 || Binder.binding(bindings[0]) !== null;
};
Binder.binding = function(string) {
var binding = string.replace(/\n/gm, ' ').match(/^\{\{(.*)\}\}$/);
return binding ? binding[1] : null;
};
Binder.prototype = {
parseQueryString: function(query) {
var params = {};
query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,
function (match, left, right) {
if (left) params[decodeURIComponent(left)] = decodeURIComponent(right);
});
return params;
},
parseAnchor: function() {
var self = this, url = this.location['get']() || "";
var anchorIndex = url.indexOf('#');
if (anchorIndex < 0) return;
var anchor = url.substring(anchorIndex + 1);
var anchorQuery = this.parseQueryString(anchor);
foreach(self.anchor, function(newValue, key) {
delete self.anchor[key];
});
foreach(anchorQuery, function(newValue, key) {
self.anchor[key] = newValue;
});
},
onUrlChange: function() {
this.parseAnchor();
this.updateView();
},
updateAnchor: function() {
var url = this.location['get']() || "";
var anchorIndex = url.indexOf('#');
if (anchorIndex > -1)
url = url.substring(0, anchorIndex);
url += "#";
var sep = '';
for (var key in this.anchor) {
var value = this.anchor[key];
if (typeof value === 'undefined' || value === null) {
delete this.anchor[key];
} else {
url += sep + encodeURIComponent(key);
if (value !== true)
url += "=" + encodeURIComponent(value);
sep = '&';
}
}
this.location['set'](url);
return url;
},
updateView: function() {
var start = new Date().getTime();
var scope = jQuery(this.doc).scope();
scope.clearInvalid();
scope.updateView();
var end = new Date().getTime();
this.updateAnchor();
foreach(this.updateListeners, function(fn) {fn();});
},
docFindWithSelf: function(exp){
var doc = jQuery(this.doc);
var selection = doc.find(exp);
if (doc.is(exp)){
selection = selection.andSelf();
}
return selection;
},
executeInit: function() {
this.docFindWithSelf("[ng-init]").each(function() {
var jThis = jQuery(this);
var scope = jThis.scope();
try {
scope.eval(jThis.attr('ng-init'));
} catch (e) {
alert("EVAL ERROR:\n" + jThis.attr('ng-init') + '\n' + toJson(e, true));
}
});
},
entity: function (scope) {
var self = this;
this.docFindWithSelf("[ng-entity]").attr("ng-watch", function() {
try {
var jNode = jQuery(this);
var decl = scope.entity(jNode.attr("ng-entity"), self.datastore);
return decl + (jNode.attr('ng-watch') || "");
} catch (e) {
log(e);
alert(e);
}
});
},
compile: function() {
var jNode = jQuery(this.doc);
if (this.config['autoSubmit']) {
var submits = this.docFindWithSelf(":submit").not("[ng-action]");
submits.attr("ng-action", "$save()");
submits.not(":disabled").not("ng-bind-attr").attr("ng-bind-attr", '{disabled:"{{$invalidWidgets}}"}');
}
this.precompile(this.doc)(this.doc, jNode.scope(), "");
this.docFindWithSelf("a[ng-action]").live('click', function (event) {
var jNode = jQuery(this);
var scope = jNode.scope();
try {
scope.eval(jNode.attr('ng-action'));
jNode.removeAttr('ng-error');
jNode.removeClass("ng-exception");
} catch (e) {
jNode.addClass("ng-exception");
jNode.attr('ng-error', toJson(e, true));
}
scope.get('$updateView')();
return false;
});
},
translateBinding: function(node, parentPath, factories) {
var path = parentPath.concat();
var offset = path.pop();
var parts = Binder.parseBindings(node.nodeValue);
if (parts.length > 1 || Binder.binding(parts[0])) {
var parent = node.parentNode;
if (isLeafNode(parent)) {
parent.setAttribute('ng-bind-template', node.nodeValue);
factories.push({path:path, fn:function(node, scope, prefix) {
return new BindUpdater(node, node.getAttribute('ng-bind-template'));
}});
} else {
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var binding = Binder.binding(part);
var newNode;
if (binding) {
newNode = document.createElement("span");
var jNewNode = jQuery(newNode);
jNewNode.attr("ng-bind", binding);
if (i === 0) {
factories.push({path:path.concat(offset + i), fn:this.ng_bind});
}
} else if (msie && part.charAt(0) == ' ') {
newNode = document.createElement("span");
newNode.innerHTML = '&nbsp;' + part.substring(1);
} else {
newNode = document.createTextNode(part);
}
parent.insertBefore(newNode, node);
}
}
parent.removeChild(node);
}
},
precompile: function(root) {
var factories = [];
this.precompileNode(root, [], factories);
return function (template, scope, prefix) {
var len = factories.length;
for (var i = 0; i < len; i++) {
var factory = factories[i];
var node = template;
var path = factory.path;
for (var j = 0; j < path.length; j++) {
node = node.childNodes[path[j]];
}
try {
scope.addWidget(factory.fn(node, scope, prefix));
} catch (e) {
alert(e);
}
}
};
},
precompileNode: function(node, path, factories) {
var nodeType = node.nodeType;
if (nodeType == Node.TEXT_NODE) {
this.translateBinding(node, path, factories);
return;
} else if (nodeType != Node.ELEMENT_NODE && nodeType != Node.DOCUMENT_NODE) {
return;
}
if (!node.getAttribute) return;
var nonBindable = node.getAttribute('ng-non-bindable');
if (nonBindable || nonBindable === "") return;
var attributes = node.attributes;
if (attributes) {
var bindings = node.getAttribute('ng-bind-attr');
node.removeAttribute('ng-bind-attr');
bindings = bindings ? fromJson(bindings) : {};
var attrLen = attributes.length;
for (var i = 0; i < attrLen; i++) {
var attr = attributes[i];
var attrName = attr.name;
// http://www.glennjones.net/Post/809/getAttributehrefbug.htm
var attrValue = msie && attrName == 'href' ?
decodeURI(node.getAttribute(attrName, 2)) : attr.value;
if (Binder.hasBinding(attrValue)) {
bindings[attrName] = attrValue;
}
}
var json = toJson(bindings);
if (json.length > 2) {
node.setAttribute("ng-bind-attr", json);
}
}
if (!node.getAttribute) log(node);
var repeaterExpression = node.getAttribute('ng-repeat');
if (repeaterExpression) {
node.removeAttribute('ng-repeat');
var precompiled = this.precompile(node);
var view = document.createComment("ng-repeat: " + repeaterExpression);
var parentNode = node.parentNode;
parentNode.insertBefore(view, node);
parentNode.removeChild(node);
function template(childScope, prefix, i) {
var clone = jQuery(node).clone();
clone.css('display', '');
clone.attr('ng-repeat-index', "" + i);
clone.data('scope', childScope);
precompiled(clone[0], childScope, prefix + i + ":");
return clone;
}
factories.push({path:path, fn:function(node, scope, prefix) {
return new RepeaterUpdater(jQuery(node), repeaterExpression, template, prefix);
}});
return;
}
if (node.getAttribute('ng-eval')) factories.push({path:path, fn:this.ng_eval});
if (node.getAttribute('ng-bind')) factories.push({path:path, fn:this.ng_bind});
if (node.getAttribute('ng-bind-attr')) factories.push({path:path, fn:this.ng_bind_attr});
if (node.getAttribute('ng-hide')) factories.push({path:path, fn:this.ng_hide});
if (node.getAttribute('ng-show')) factories.push({path:path, fn:this.ng_show});
if (node.getAttribute('ng-class')) factories.push({path:path, fn:this.ng_class});
if (node.getAttribute('ng-class-odd')) factories.push({path:path, fn:this.ng_class_odd});
if (node.getAttribute('ng-class-even')) factories.push({path:path, fn:this.ng_class_even});
if (node.getAttribute('ng-style')) factories.push({path:path, fn:this.ng_style});
if (node.getAttribute('ng-watch')) factories.push({path:path, fn:this.ng_watch});
var nodeName = node.nodeName;
if ((nodeName == 'INPUT' ) ||
nodeName == 'TEXTAREA' ||
nodeName == 'SELECT' ||
nodeName == 'BUTTON') {
var self = this;
factories.push({path:path, fn:function(node, scope, prefix) {
node.name = prefix + node.name.split(":").pop();
return self.widgetFactory.createController(jQuery(node), scope);
}});
}
if (nodeName == 'OPTION') {
var html = jQuery('<select/>').append(jQuery(node).clone()).html();
if (!html.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) {
if (Binder.hasBinding(node.text)) {
jQuery(node).attr('ng-bind-attr', angular.toJson({'value':node.text}));
} else {
node.value = node.text;
}
}
}
var children = node.childNodes;
for (var k = 0; k < children.length; k++) {
this.precompileNode(children[k], path.concat(k), factories);
}
},
ng_eval: function(node) {
return new EvalUpdater(node, node.getAttribute('ng-eval'));
},
ng_bind: function(node) {
return new BindUpdater(node, "{{" + node.getAttribute('ng-bind') + "}}");
},
ng_bind_attr: function(node) {
return new BindAttrUpdater(node, fromJson(node.getAttribute('ng-bind-attr')));
},
ng_hide: function(node) {
return new HideUpdater(node, node.getAttribute('ng-hide'));
},
ng_show: function(node) {
return new ShowUpdater(node, node.getAttribute('ng-show'));
},
ng_class: function(node) {
return new ClassUpdater(node, node.getAttribute('ng-class'));
},
ng_class_even: function(node) {
return new ClassEvenUpdater(node, node.getAttribute('ng-class-even'));
},
ng_class_odd: function(node) {
return new ClassOddUpdater(node, node.getAttribute('ng-class-odd'));
},
ng_style: function(node) {
return new StyleUpdater(node, node.getAttribute('ng-style'));
},
ng_watch: function(node, scope) {
scope.watch(node.getAttribute('ng-watch'));
}
};

65
src/delete/Model.js Normal file
View file

@ -0,0 +1,65 @@
// Single $ is special and does not get searched
// Double $$ is special an is client only (does not get sent to server)
function Model(entity, initial) {
this['$$entity'] = entity;
this['$loadFrom'](initial||{});
this['$entity'] = entity['title'];
this['$migrate']();
};
Model.copyDirectFields = function(src, dst) {
if (src === dst || !src || !dst) return;
var isDataField = function(src, dst, field) {
return (field.substring(0,2) !== '$$') &&
(typeof src[field] !== 'function') &&
(typeof dst[field] !== 'function');
};
for (var field in dst) {
if (isDataField(src, dst, field))
delete dst[field];
}
for (field in src) {
if (isDataField(src, dst, field))
dst[field] = src[field];
}
};
extend(Model.prototype, {
'$migrate': function() {
merge(this['$$entity']['defaults'], this);
return this;
},
'$merge': function(other) {
merge(other, this);
return this;
},
'$save': function(callback) {
this['$$entity'].datastore.save(this, callback === true ? undefined : callback);
if (callback === true) this['$$entity'].datastore.flush();
return this;
},
'$delete': function(callback) {
this['$$entity'].datastore.remove(this, callback === true ? undefined : callback);
if (callback === true) this['$$entity'].datastore.flush();
return this;
},
'$loadById': function(id, callback) {
this['$$entity'].datastore.load(this, id, callback);
return this;
},
'$loadFrom': function(other) {
Model.copyDirectFields(other, this);
return this;
},
'$saveTo': function(other) {
Model.copyDirectFields(this, other);
return this;
}
});

407
src/delete/Scope.js Normal file
View file

@ -0,0 +1,407 @@
function Scope(initialState, name) {
var self = this;
self.widgets = [];
self.evals = [];
self.watchListeners = {};
self.name = name;
initialState = initialState || {};
var State = function(){};
State.prototype = initialState;
self.state = new State();
extend(self.state, {
'$parent': initialState,
'$watch': bind(self, self.addWatchListener),
'$eval': bind(self, self.eval),
'$bind': bind(self, bind, self),
// change name to autoEval?
'$addEval': bind(self, self.addEval),
'$updateView': bind(self, self.updateView)
});
if (name == "ROOT") {
self.state['$root'] = self.state;
}
};
Scope.expressionCache = {};
Scope.getter = function(instance, path) {
if (!path) return instance;
var element = path.split('.');
var key;
var lastInstance = instance;
var len = element.length;
for ( var i = 0; i < len; i++) {
key = element[i];
if (!key.match(/^[\$\w][\$\w\d]*$/))
throw "Expression '" + path + "' is not a valid expression for accesing variables.";
if (instance) {
lastInstance = instance;
instance = instance[key];
}
if (_.isUndefined(instance) && key.charAt(0) == '$') {
var type = angular['Global']['typeOf'](lastInstance);
type = angular[type.charAt(0).toUpperCase()+type.substring(1)];
var fn = type ? type[[key.substring(1)]] : undefined;
if (fn) {
instance = _.bind(fn, lastInstance, lastInstance);
return instance;
}
}
}
if (typeof instance === 'function' && !instance['$$factory']) {
return bind(lastInstance, instance);
}
return instance;
};
Scope.setter = function(instance, path, value){
var element = path.split('.');
for ( var i = 0; element.length > 1; i++) {
var key = element.shift();
var newInstance = instance[key];
if (!newInstance) {
newInstance = {};
instance[key] = newInstance;
}
instance = newInstance;
}
instance[element.shift()] = value;
return value;
};
Scope.prototype = {
// TODO: rename to update? or eval?
updateView: function() {
var self = this;
this.fireWatchers();
foreach(this.widgets, function(widget){
self.evalWidget(widget, "", {}, function(){
this.updateView(self);
});
});
foreach(this.evals, bind(this, this.apply));
},
addWidget: function(controller) {
if (controller) this.widgets.push(controller);
},
addEval: function(fn, listener) {
// todo: this should take a function/string and a listener
// todo: this is a hack, which will need to be cleaned up.
var self = this,
listenFn = listener || noop,
expr = self.compile(fn);
this.evals.push(function(){
self.apply(listenFn, expr());
});
},
isProperty: function(exp) {
for ( var i = 0; i < exp.length; i++) {
var ch = exp.charAt(i);
if (ch!='.' && !Lexer.prototype.isIdent(ch)) {
return false;
}
}
return true;
},
get: function(path) {
// log('SCOPE.get', path, Scope.getter(this.state, path));
return Scope.getter(this.state, path);
},
set: function(path, value) {
// log('SCOPE.set', path, value);
var instance = this.state;
return Scope.setter(instance, path, value);
},
setEval: function(expressionText, value) {
this.eval(expressionText + "=" + toJson(value));
},
compile: function(exp) {
if (isFunction(exp)) return bind(this.state, exp);
var expFn = Scope.expressionCache[exp], self = this;
if (!expFn) {
var parser = new Parser(exp);
expFn = parser.statements();
parser.assertAllConsumed();
Scope.expressionCache[exp] = expFn;
}
return function(context){
context = context || {};
context.self = self.state;
context.scope = self;
return expFn.call(self, context);
};
},
eval: function(exp, context) {
// log('Scope.eval', expressionText);
return this.compile(exp)(context);
},
//TODO: Refactor. This function needs to be an execution closure for widgets
// move to widgets
// remove expression, just have inner closure.
evalWidget: function(widget, expression, context, onSuccess, onFailure) {
try {
var value = this.eval(expression, context);
if (widget.hasError) {
widget.hasError = false;
jQuery(widget.view).
removeClass('ng-exception').
removeAttr('ng-error');
}
if (onSuccess) {
value = onSuccess.apply(widget, [value]);
}
return true;
} catch (e){
var jsonError = toJson(e, true);
error('Eval Widget Error:', jsonError);
widget.hasError = true;
jQuery(widget.view).
addClass('ng-exception').
attr('ng-error', jsonError);
if (onFailure) {
onFailure.apply(widget, [e, jsonError]);
}
return false;
}
},
validate: function(expressionText, value, element) {
var expression = Scope.expressionCache[expressionText];
if (!expression) {
expression = new Parser(expressionText).validator();
Scope.expressionCache[expressionText] = expression;
}
var self = {scope:this, self:this.state, '$element':element};
return expression(self)(self, value);
},
entity: function(entityDeclaration, datastore) {
var expression = new Parser(entityDeclaration).entityDeclaration();
return expression({scope:this, datastore:datastore});
},
clearInvalid: function() {
var invalid = this.state['$invalidWidgets'];
while(invalid.length > 0) {invalid.pop();}
},
markInvalid: function(widget) {
this.state['$invalidWidgets'].push(widget);
},
watch: function(declaration) {
var self = this;
new Parser(declaration).watch()({
scope:this,
addListener:function(watch, exp){
self.addWatchListener(watch, function(n,o){
try {
return exp({scope:self}, n, o);
} catch(e) {
alert(e);
}
});
}
});
},
addWatchListener: function(watchExpression, listener) {
// TODO: clean me up!
if (!isFunction(listener)) {
listener = this.compile(listener);
}
var watcher = this.watchListeners[watchExpression];
if (!watcher) {
watcher = {listeners:[], expression:watchExpression};
this.watchListeners[watchExpression] = watcher;
}
watcher.listeners.push(listener);
},
fireWatchers: function() {
var self = this, fired = false;
foreach(this.watchListeners, function(watcher) {
var value = self.eval(watcher.expression);
if (value !== watcher.lastValue) {
foreach(watcher.listeners, function(listener){
listener(value, watcher.lastValue);
fired = true;
});
watcher.lastValue = value;
}
});
return fired;
},
apply: function(fn) {
fn.apply(this.state, slice.call(arguments, 1, arguments.length));
}
};
//////////////////////////////
function getter(instance, path) {
if (!path) return instance;
var element = path.split('.');
var key;
var lastInstance = instance;
var len = element.length;
for ( var i = 0; i < len; i++) {
key = element[i];
if (!key.match(/^[\$\w][\$\w\d]*$/))
throw "Expression '" + path + "' is not a valid expression for accesing variables.";
if (instance) {
lastInstance = instance;
instance = instance[key];
}
if (_.isUndefined(instance) && key.charAt(0) == '$') {
var type = angular['Global']['typeOf'](lastInstance);
type = angular[type.charAt(0).toUpperCase()+type.substring(1)];
var fn = type ? type[[key.substring(1)]] : undefined;
if (fn) {
instance = _.bind(fn, lastInstance, lastInstance);
return instance;
}
}
}
if (typeof instance === 'function' && !instance['$$factory']) {
return bind(lastInstance, instance);
}
return instance;
};
function setter(instance, path, value){
var element = path.split('.');
for ( var i = 0; element.length > 1; i++) {
var key = element.shift();
var newInstance = instance[key];
if (!newInstance) {
newInstance = {};
instance[key] = newInstance;
}
instance = newInstance;
}
instance[element.shift()] = value;
return value;
};
var compileCache = {};
function expressionCompile(exp){
if (isFunction(exp)) return exp;
var expFn = compileCache[exp];
if (!expFn) {
var parser = new Parser(exp);
expFn = parser.statements();
parser.assertAllConsumed();
compileCache[exp] = expFn;
}
// return expFn
// TODO(remove this hack)
return function(){
return expFn({
scope: {
set: this.$set,
get: this.$get
}
});
};
};
var NON_RENDERABLE_ELEMENTS = {
'#text': 1, '#comment':1, 'TR':1, 'TH':1
};
function isRenderableElement(element){
return element && element[0] && !NON_RENDERABLE_ELEMENTS[element[0].nodeName];
}
function rethrow(e) { throw e; }
function errorHandlerFor(element) {
while (!isRenderableElement(element)) {
element = element.parent() || jqLite(document.body);
}
return function(error) {
element.attr('ng-error', angular.toJson(error));
element.addClass('ng-exception');
};
}
function createScope(parent, Class) {
function Parent(){}
function API(){}
function Behavior(){}
var instance, behavior, api, watchList = [], evalList = [];
Class = Class || noop;
parent = Parent.prototype = parent || {};
api = API.prototype = new Parent();
behavior = Behavior.prototype = extend(new API(), Class.prototype);
instance = new Behavior();
extend(api, {
$parent: parent,
$bind: bind(instance, bind, instance),
$get: bind(instance, getter, instance),
$set: bind(instance, setter, instance),
$eval: function(exp) {
if (isDefined(exp)) {
return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length));
} else {
foreach(evalList, function(eval) {
instance.$tryEval(eval.fn, eval.handler);
});
foreach(watchList, function(watch) {
var value = instance.$tryEval(watch.watch, watch.handler);
if (watch.last !== value) {
instance.$tryEval(watch.listener, watch.handler, value, watch.last);
watch.last = value;
}
});
}
},
$tryEval: function (expression, exceptionHandler) {
try {
return expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length));
} catch (e) {
error(e);
if (isFunction(exceptionHandler)) {
exceptionHandler(e);
} else if (exceptionHandler) {
errorHandlerFor(exceptionHandler)(e);
}
}
},
$watch: function(watchExp, listener, exceptionHandler) {
var watch = expressionCompile(watchExp);
watchList.push({
watch: watch,
last: watch.call(instance),
handler: exceptionHandler,
listener:expressionCompile(listener)
});
},
$onEval: function(expr, exceptionHandler){
evalList.push({
fn: expressionCompile(expr),
handler: exceptionHandler
});
}
});
Class.apply(instance, slice.call(arguments, 2, arguments.length));
return instance;
}

806
src/delete/Widgets.js Normal file
View file

@ -0,0 +1,806 @@
function WidgetFactory(serverUrl, database) {
this.nextUploadId = 0;
this.serverUrl = serverUrl;
this.database = database;
if (window['swfobject']) {
this.createSWF = window['swfobject']['createSWF'];
} else {
this.createSWF = function(){
alert("ERROR: swfobject not loaded!");
};
}
};
WidgetFactory.prototype = {
createController: function(input, scope) {
var controller;
var type = input.attr('type').toLowerCase();
var exp = input.attr('name');
if (exp) exp = exp.split(':').pop();
var event = "change";
var bubbleEvent = true;
var formatter = angularFormatter[input.attr('ng-format')] || angularFormatter['noop'];
if (type == 'button' || type == 'submit' || type == 'reset' || type == 'image') {
controller = new ButtonController(input[0], exp, formatter);
event = "click";
bubbleEvent = false;
} else if (type == 'text' || type == 'textarea' || type == 'hidden' || type == 'password') {
controller = new TextController(input[0], exp, formatter);
event = "keyup change";
} else if (type == 'checkbox') {
controller = new CheckboxController(input[0], exp, formatter);
event = "click";
} else if (type == 'radio') {
controller = new RadioController(input[0], exp, formatter);
event="click";
} else if (type == 'select-one') {
controller = new SelectController(input[0], exp, formatter);
} else if (type == 'select-multiple') {
controller = new MultiSelectController(input[0], exp, formatter);
} else if (type == 'file') {
controller = this.createFileController(input, exp, formatter);
} else {
throw 'Unknown type: ' + type;
}
input.data('controller', controller);
var updateView = scope.get('$updateView');
var action = function() {
if (controller.updateModel(scope)) {
var action = jQuery(controller.view).attr('ng-action') || "";
if (scope.evalWidget(controller, action)) {
updateView(scope);
}
}
return bubbleEvent;
};
jQuery(controller.view, ":input").
bind(event, action);
return controller;
},
createFileController: function(fileInput) {
var uploadId = '__uploadWidget_' + (this.nextUploadId++);
var view = FileController.template(uploadId);
fileInput.after(view);
var att = {
'data':this.serverUrl + "/admin/ServerAPI.swf",
'width':"95", 'height':"20", 'align':"top",
'wmode':"transparent"};
var par = {
'flashvars':"uploadWidgetId=" + uploadId,
'allowScriptAccess':"always"};
var swfNode = this.createSWF(att, par, uploadId);
fileInput.remove();
var cntl = new FileController(view, fileInput[0].name, swfNode, this.serverUrl + "/data/" + this.database);
jQuery(swfNode).parent().data('controller', cntl);
return cntl;
}
};
/////////////////////
// FileController
///////////////////////
function FileController(view, scopeName, uploader, databaseUrl) {
this.view = view;
this.uploader = uploader;
this.scopeName = scopeName;
this.attachmentsPath = databaseUrl + '/_attachments';
this.value = null;
this.lastValue = undefined;
};
angularCallbacks['flashEvent'] = function(id, event, args) {
var object = document.getElementById(id);
var jobject = jQuery(object);
var controller = jobject.parent().data("controller");
FileController.prototype[event].apply(controller, args);
_.defer(jobject.scope().get('$updateView'));
};
FileController.template = function(id) {
return jQuery('<span class="ng-upload-widget">' +
'<input type="checkbox" ng-non-bindable="true"/>' +
'<object id="' + id + '" />' +
'<a></a>' +
'<span/>' +
'</span>');
};
extend(FileController.prototype, {
'cancel': noop,
'complete': noop,
'httpStatus': function(status) {
alert("httpStatus:" + this.scopeName + " status:" + status);
},
'ioError': function() {
alert("ioError:" + this.scopeName);
},
'open': function() {
alert("open:" + this.scopeName);
},
'progress':noop,
'securityError': function() {
alert("securityError:" + this.scopeName);
},
'uploadCompleteData': function(data) {
var value = fromJson(data);
value.url = this.attachmentsPath + '/' + value.id + '/' + value.text;
this.view.find("input").attr('checked', true);
var scope = this.view.scope();
this.value = value;
this.updateModel(scope);
this.value = null;
},
'select': function(name, size, type) {
this.name = name;
this.view.find("a").text(name).attr('href', name);
this.view.find("span").text(angular['filter']['bytes'](size));
this.upload();
},
updateModel: function(scope) {
var isChecked = this.view.find("input").attr('checked');
var value = isChecked ? this.value : null;
if (this.lastValue === value) {
return false;
} else {
scope.set(this.scopeName, value);
return true;
}
},
updateView: function(scope) {
var modelValue = scope.get(this.scopeName);
if (modelValue && this.value !== modelValue) {
this.value = modelValue;
this.view.find("a").
attr("href", this.value.url).
text(this.value.text);
this.view.find("span").text(angular['filter']['bytes'](this.value.size));
}
this.view.find("input").attr('checked', !!modelValue);
},
upload: function() {
if (this.name) {
this.uploader['uploadFile'](this.attachmentsPath);
}
}
});
///////////////////////
// NullController
///////////////////////
function NullController(view) {this.view = view;};
NullController.prototype = {
updateModel: function() { return true; },
updateView: noop
};
NullController.instance = new NullController();
///////////////////////
// ButtonController
///////////////////////
var ButtonController = NullController;
///////////////////////
// TextController
///////////////////////
function TextController(view, exp, formatter) {
this.view = view;
this.formatter = formatter;
this.exp = exp;
this.validator = view.getAttribute('ng-validate');
this.required = typeof view.attributes['ng-required'] != "undefined";
this.lastErrorText = null;
this.lastValue = undefined;
this.initialValue = this.formatter['parse'](view.value);
var widget = view.getAttribute('ng-widget');
if (widget === 'datepicker') {
jQuery(view).datepicker();
}
};
TextController.prototype = {
updateModel: function(scope) {
var value = this.formatter['parse'](this.view.value);
if (this.lastValue === value) {
return false;
} else {
scope.setEval(this.exp, value);
this.lastValue = value;
return true;
}
},
updateView: function(scope) {
var view = this.view;
var value = scope.get(this.exp);
if (typeof value === "undefined") {
value = this.initialValue;
scope.setEval(this.exp, value);
}
value = value ? value : '';
if (!_(this.lastValue).isEqual(value)) {
view.value = this.formatter['format'](value);
this.lastValue = value;
}
var isValidationError = false;
view.removeAttribute('ng-error');
if (this.required) {
isValidationError = !(value && $.trim("" + value).length > 0);
}
var errorText = isValidationError ? "Required Value" : null;
if (!isValidationError && this.validator && value) {
errorText = scope.validate(this.validator, value, view);
isValidationError = !!errorText;
}
if (this.lastErrorText !== errorText) {
this.lastErrorText = isValidationError;
if (errorText && isVisible(view)) {
view.setAttribute('ng-error', errorText);
scope.markInvalid(this);
}
jQuery(view).toggleClass('ng-validation-error', isValidationError);
}
}
};
///////////////////////
// CheckboxController
///////////////////////
function CheckboxController(view, exp, formatter) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.formatter = formatter;
this.initialValue = this.formatter['parse'](view.checked ? view.value : "");
};
CheckboxController.prototype = {
updateModel: function(scope) {
var input = this.view;
var value = input.checked ? input.value : '';
value = this.formatter['parse'](value);
value = this.formatter['format'](value);
if (this.lastValue === value) {
return false;
} else {
scope.setEval(this.exp, this.formatter['parse'](value));
this.lastValue = value;
return true;
}
},
updateView: function(scope) {
var input = this.view;
var value = scope.eval(this.exp);
if (typeof value === "undefined") {
value = this.initialValue;
scope.setEval(this.exp, value);
}
input.checked = this.formatter['parse'](input.value) == value;
}
};
///////////////////////
// SelectController
///////////////////////
function SelectController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = view.value;
};
SelectController.prototype = {
updateModel: function(scope) {
var input = this.view;
if (input.selectedIndex < 0) {
scope.setEval(this.exp, null);
} else {
var value = this.view.value;
if (this.lastValue === value) {
return false;
} else {
scope.setEval(this.exp, value);
this.lastValue = value;
return true;
}
}
},
updateView: function(scope) {
var input = this.view;
var value = scope.get(this.exp);
if (typeof value === 'undefined') {
value = this.initialValue;
scope.setEval(this.exp, value);
}
if (value !== this.lastValue) {
input.value = value ? value : "";
this.lastValue = value;
}
}
};
///////////////////////
// MultiSelectController
///////////////////////
function MultiSelectController(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = this.selected();
};
MultiSelectController.prototype = {
selected: function () {
var value = [];
var options = this.view.options;
for ( var i = 0; i < options.length; i++) {
var option = options[i];
if (option.selected) {
value.push(option.value);
}
}
return value;
},
updateModel: function(scope) {
var value = this.selected();
// TODO: This is wrong! no caching going on here as we are always comparing arrays
if (this.lastValue === value) {
return false;
} else {
scope.setEval(this.exp, value);
this.lastValue = value;
return true;
}
},
updateView: function(scope) {
var input = this.view;
var selected = scope.get(this.exp);
if (typeof selected === "undefined") {
selected = this.initialValue;
scope.setEval(this.exp, selected);
}
if (selected !== this.lastValue) {
var options = input.options;
for ( var i = 0; i < options.length; i++) {
var option = options[i];
option.selected = _.include(selected, option.value);
}
this.lastValue = selected;
}
}
};
///////////////////////
// RadioController
///////////////////////
function RadioController(view, exp) {
this.view = view;
this.exp = exp;
this.lastChecked = undefined;
this.lastValue = undefined;
this.inputValue = view.value;
this.initialValue = view.checked ? view.value : null;
};
RadioController.prototype = {
updateModel: function(scope) {
var input = this.view;
if (this.lastChecked) {
return false;
} else {
input.checked = true;
this.lastValue = scope.setEval(this.exp, this.inputValue);
this.lastChecked = true;
return true;
}
},
updateView: function(scope) {
var input = this.view;
var value = scope.get(this.exp);
if (this.initialValue && typeof value === "undefined") {
value = this.initialValue;
scope.setEval(this.exp, value);
}
if (this.lastValue != value) {
this.lastChecked = input.checked = this.inputValue == (''+value);
this.lastValue = value;
}
}
};
///////////////////////
//ElementController
///////////////////////
function BindUpdater(view, exp) {
this.view = view;
this.exp = Binder.parseBindings(exp);
this.hasError = false;
};
BindUpdater.toText = function(obj) {
var e = escapeHtml;
switch(typeof obj) {
case "string":
case "boolean":
case "number":
return e(obj);
case "function":
return BindUpdater.toText(obj());
case "object":
if (isNode(obj)) {
return outerHTML(obj);
} else if (obj instanceof angular.filter.Meta) {
switch(typeof obj.html) {
case "string":
case "number":
return obj.html;
case "function":
return obj.html();
case "object":
if (isNode(obj.html))
return outerHTML(obj.html);
default:
break;
}
switch(typeof obj.text) {
case "string":
case "number":
return e(obj.text);
case "function":
return e(obj.text());
default:
break;
}
}
if (obj === null)
return "";
return e(toJson(obj, true));
default:
return "";
}
};
BindUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
var html = [];
var parts = this.exp;
var length = parts.length;
for(var i=0; i<length; i++) {
var part = parts[i];
var binding = Binder.binding(part);
if (binding) {
scope.evalWidget(this, binding, {$element:this.view}, function(value){
html.push(BindUpdater.toText(value));
}, function(e, text){
setHtml(this.view, text);
});
if (this.hasError) {
return;
}
} else {
html.push(escapeHtml(part));
}
}
setHtml(this.view, html.join(''));
}
};
function BindAttrUpdater(view, attrs) {
this.view = view;
this.attrs = attrs;
};
BindAttrUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
var jNode = jQuery(this.view);
var attributeTemplates = this.attrs;
if (this.hasError) {
this.hasError = false;
jNode.
removeClass('ng-exception').
removeAttr('ng-error');
}
var isImage = jNode.is('img');
for (var attrName in attributeTemplates) {
var attributeTemplate = Binder.parseBindings(attributeTemplates[attrName]);
var attrValues = [];
for ( var i = 0; i < attributeTemplate.length; i++) {
var binding = Binder.binding(attributeTemplate[i]);
if (binding) {
try {
var value = scope.eval(binding, {$element:jNode[0], attrName:attrName});
if (value && (value.constructor !== array || value.length !== 0))
attrValues.push(value);
} catch (e) {
this.hasError = true;
error('BindAttrUpdater', e);
var jsonError = toJson(e, true);
attrValues.push('[' + jsonError + ']');
jNode.
addClass('ng-exception').
attr('ng-error', jsonError);
}
} else {
attrValues.push(attributeTemplate[i]);
}
}
var attrValue = attrValues.length ? attrValues.join('') : null;
if(isImage && attrName == 'src' && !attrValue)
attrValue = scope.get('$config.blankImage');
jNode.attr(attrName, attrValue);
}
}
};
function EvalUpdater(view, exp) {
this.view = view;
this.exp = exp;
this.hasError = false;
};
EvalUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.exp);
}
};
function HideUpdater(view, exp) { this.view = view; this.exp = exp; };
HideUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.exp, {}, function(hideValue){
var view = jQuery(this.view);
if (toBoolean(hideValue)) {
view.hide();
} else {
view.show();
}
});
}
};
function ShowUpdater(view, exp) { this.view = view; this.exp = exp; };
ShowUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.exp, {}, function(hideValue){
var view = jQuery(this.view);
if (toBoolean(hideValue)) {
view.show();
} else {
view.hide();
}
});
}
};
function ClassUpdater(view, exp) { this.view = view; this.exp = exp; };
ClassUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.exp, {}, function(classValue){
if (classValue !== null && classValue !== undefined) {
this.view.className = classValue;
}
});
}
};
function ClassEvenUpdater(view, exp) { this.view = view; this.exp = exp; };
ClassEvenUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.exp, {}, function(classValue){
var index = scope.get('$index');
jQuery(this.view).toggleClass(classValue, index % 2 === 1);
});
}
};
function ClassOddUpdater(view, exp) { this.view = view; this.exp = exp; };
ClassOddUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.exp, {}, function(classValue){
var index = scope.get('$index');
jQuery(this.view).toggleClass(classValue, index % 2 === 0);
});
}
};
function StyleUpdater(view, exp) { this.view = view; this.exp = exp; };
StyleUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.exp, {}, function(styleValue){
jQuery(this.view).attr('style', "").css(styleValue);
});
}
};
///////////////////////
// RepeaterUpdater
///////////////////////
function RepeaterUpdater(view, repeaterExpression, template, prefix) {
this.view = view;
this.template = template;
this.prefix = prefix;
this.children = [];
var match = repeaterExpression.match(/^\s*(.+)\s+in\s+(.*)\s*$/);
if (! match) {
throw "Expected ng-repeat in form of 'item in collection' but got '" +
repeaterExpression + "'.";
}
var keyValue = match[1];
this.iteratorExp = match[2];
match = keyValue.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
if (!match) {
throw "'item' in 'item in collection' should be identifier or (key, value) but get '" +
keyValue + "'.";
}
this.valueExp = match[3] || match[1];
this.keyExp = match[2];
};
RepeaterUpdater.prototype = {
updateModel: noop,
updateView: function(scope) {
scope.evalWidget(this, this.iteratorExp, {}, function(iterator){
var self = this;
if (!iterator) {
iterator = [];
if (scope.isProperty(this.iteratorExp)) {
scope.set(this.iteratorExp, iterator);
}
}
var childrenLength = this.children.length;
var cursor = this.view;
var time = 0;
var child = null;
var keyExp = this.keyExp;
var valueExp = this.valueExp;
var iteratorCounter = 0;
foreach(iterator, function(value, key){
if (iteratorCounter < childrenLength) {
// reuse children
child = self.children[iteratorCounter];
child.scope.set(valueExp, value);
} else {
// grow children
var name = self.prefix +
valueExp + " in " + self.iteratorExp + "[" + iteratorCounter + "]";
var childScope = new Scope(scope.state, name);
childScope.set('$index', iteratorCounter);
if (keyExp)
childScope.set(keyExp, key);
childScope.set(valueExp, value);
child = { scope:childScope, element:self.template(childScope, self.prefix, iteratorCounter) };
cursor.after(child.element);
self.children.push(child);
}
cursor = child.element;
var s = new Date().getTime();
child.scope.updateView();
time += new Date().getTime() - s;
iteratorCounter++;
});
// shrink children
for ( var r = childrenLength; r > iteratorCounter; --r) {
this.children.pop().element.remove();
}
// Special case for option in select
if (child && child.element[0].nodeName === "OPTION") {
var select = jQuery(child.element[0].parentNode);
var cntl = select.data('controller');
if (cntl) {
cntl.lastValue = undefined;
cntl.updateView(scope);
}
}
});
}
};
//////////////////////////////////
// PopUp
//////////////////////////////////
function PopUp(doc) {
this.doc = doc;
};
PopUp.OUT_EVENT = "mouseleave mouseout click dblclick keypress keyup";
PopUp.onOver = function(e) {
PopUp.onOut();
var jNode = jQuery(this);
jNode.bind(PopUp.OUT_EVENT, PopUp.onOut);
var position = jNode.position();
var de = document.documentElement;
var w = self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
var hasArea = w - position.left;
var width = 300;
var title = jNode.hasClass("ng-exception") ? "EXCEPTION:" : "Validation error...";
var msg = jNode.attr("ng-error");
var x;
var arrowPos = hasArea>(width+75) ? "left" : "right";
var tip = jQuery(
"<div id='ng-callout' style='width:"+width+"px'>" +
"<div class='ng-arrow-"+arrowPos+"'/>" +
"<div class='ng-title'>"+title+"</div>" +
"<div class='ng-content'>"+msg+"</div>" +
"</div>");
jQuery("body").append(tip);
if(arrowPos === 'left'){
x = position.left + this.offsetWidth + 11;
}else{
x = position.left - (width + 15);
tip.find('.ng-arrow-right').css({left:width+1});
}
tip.css({left: x+"px", top: (position.top - 3)+"px"});
return true;
};
PopUp.onOut = function() {
jQuery('#ng-callout').
unbind(PopUp.OUT_EVENT, PopUp.onOut).
remove();
return true;
};
PopUp.prototype = {
bind: function () {
var self = this;
this.doc.find('.ng-validation-error,.ng-exception').
live("mouseover", PopUp.onOver);
}
};
//////////////////////////////////
// Status
//////////////////////////////////
function NullStatus(body) {
};
NullStatus.prototype = {
beginRequest:function(){},
endRequest:function(){}
};
function Status(body) {
this.requestCount = 0;
this.body = body;
};
Status.DOM ='<div id="ng-spacer"></div><div id="ng-loading">loading....</div>';
Status.prototype = {
beginRequest: function () {
if (this.requestCount === 0) {
(this.loader = this.loader || this.body.append(Status.DOM).find("#ng-loading")).show();
}
this.requestCount++;
},
endRequest: function () {
this.requestCount--;
if (this.requestCount === 0) {
this.loader.hide("fold");
}
}
};

261
src/directives.js Normal file
View file

@ -0,0 +1,261 @@
angularDirective("ng-init", function(expression){
return function(element){
this.$tryEval(expression, element);
};
});
angularDirective("ng-controller", function(expression){
return function(element){
var controller = getter(window, expression, true) || getter(this, expression, true);
if (!controller)
throw "Can not find '"+expression+"' controller.";
if (!isFunction(controller))
throw "Reference '"+expression+"' is not a class.";
this.$become(controller);
(this.init || noop)();
};
});
angularDirective("ng-eval", function(expression){
return function(element){
this.$onEval(expression, element);
};
});
angularDirective("ng-bind", function(expression){
return function(element) {
var lastValue = noop, lastError = noop;
this.$onEval(function() {
var error,
value = this.$tryEval(expression, function(e){
error = toJson(e);
}),
isHtml,
isDomElement;
if (lastValue === value && lastError == error) return;
isHtml = value instanceof HTML,
isDomElement = isElement(value);
if (!isHtml && !isDomElement && isObject(value)) {
value = toJson(value);
}
if (value != lastValue || error != lastError) {
lastValue = value;
lastError = error;
elementError(element, NG_EXCEPTION, error);
if (error) value = error;
if (isHtml) {
element.html(value.html);
} else if (isDomElement) {
element.html('');
element.append(value);
} else {
element.text(value);
}
}
}, element);
};
});
var bindTemplateCache = {};
function compileBindTemplate(template){
var fn = bindTemplateCache[template];
if (!fn) {
var bindings = [];
foreach(parseBindings(template), function(text){
var exp = binding(text);
bindings.push(exp ? function(element){
var error, value = this.$tryEval(exp, function(e){
error = toJson(e);
});
elementError(element, NG_EXCEPTION, error);
return error ? error : value;
} : function() {
return text;
});
});
bindTemplateCache[template] = fn = function(element){
var parts = [], self = this;
for ( var i = 0; i < bindings.length; i++) {
var value = bindings[i].call(self, element);
if (isElement(value))
value = '';
else if (isObject(value))
value = toJson(value, true);
parts.push(value);
};
return parts.join('');
};
}
return fn;
}
angularDirective("ng-bind-template", function(expression){
var templateFn = compileBindTemplate(expression);
return function(element) {
var lastValue;
this.$onEval(function() {
var value = templateFn.call(this, element);
if (value != lastValue) {
element.text(value);
lastValue = value;
}
}, element);
};
});
var REMOVE_ATTRIBUTES = {
'disabled':'disabled',
'readonly':'readOnly',
'checked':'checked'
};
angularDirective("ng-bind-attr", function(expression){
return function(element){
var lastValue = {};
this.$onEval(function(){
var values = this.$eval(expression);
for(var key in values) {
var value = compileBindTemplate(values[key]).call(this, element),
specialName = REMOVE_ATTRIBUTES[lowercase(key)];
if (lastValue[key] !== value) {
lastValue[key] = value;
if (specialName) {
if (element[specialName] = toBoolean(value)) {
element.attr(specialName, value);
} else {
element.removeAttr(key);
}
(element.data('$validate')||noop)();
} else {
element.attr(key, value);
}
}
};
}, element);
};
});
angularWidget("@ng-non-bindable", noop);
angularWidget("@ng-repeat", function(expression, element){
element.removeAttr('ng-repeat');
element.replaceWith(this.comment("ng-repeat: " + expression));
var template = this.compile(element);
return function(reference){
var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
lhs, rhs, valueIdent, keyIdent;
if (! match) {
throw "Expected ng-repeat in form of 'item in collection' but got '" +
expression + "'.";
}
lhs = match[1];
rhs = match[2];
match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
if (!match) {
throw "'item' in 'item in collection' should be identifier or (key, value) but got '" +
keyValue + "'.";
}
valueIdent = match[3] || match[1];
keyIdent = match[2];
if (isUndefined(this.$eval(rhs))) this.$set(rhs, []);
var children = [], currentScope = this;
this.$onEval(function(){
var index = 0, childCount = children.length, childScope, lastElement = reference,
collection = this.$tryEval(rhs, reference);
for ( var key in collection) {
if (index < childCount) {
// reuse existing child
childScope = children[index];
childScope[valueIdent] = collection[key];
if (keyIdent) childScope[keyIdent] = key;
} else {
// grow children
childScope = template(element.clone(), createScope(currentScope));
childScope[valueIdent] = collection[key];
if (keyIdent) childScope[keyIdent] = key;
lastElement.after(childScope.$element);
childScope.$index = index;
childScope.$element.attr('ng-repeat-index', index);
childScope.$init();
children.push(childScope);
}
childScope.$eval();
lastElement = childScope.$element;
index ++;
};
// shrink children
while(children.length > index) {
children.pop().$element.remove();
}
}, reference);
};
});
angularDirective("ng-click", function(expression, element){
return function(element){
var self = this;
element.bind('click', function(){
self.$tryEval(expression, element);
self.$root.$eval();
return false;
});
};
});
angularDirective("ng-watch", function(expression, element){
return function(element){
var self = this;
new Parser(expression).watch()({
addListener:function(watch, exp){
self.$watch(watch, function(){
return exp(self);
}, element);
}
});
};
});
function ngClass(selector) {
return function(expression, element){
var existing = element[0].className + ' ';
return function(element){
this.$onEval(function(){
var value = this.$eval(expression);
if (selector(this.$index)) {
if (isArray(value)) value = value.join(' ');
element[0].className = trim(existing + value);
}
}, element);
};
};
}
angularDirective("ng-class", ngClass(function(){return true;}));
angularDirective("ng-class-odd", ngClass(function(i){return i % 2 === 0;}));
angularDirective("ng-class-even", ngClass(function(i){return i % 2 === 1;}));
angularDirective("ng-show", function(expression, element){
return function(element){
this.$onEval(function(){
element.css('display', toBoolean(this.$eval(expression)) ? '' : 'none');
}, element);
};
});
angularDirective("ng-hide", function(expression, element){
return function(element){
this.$onEval(function(){
element.css('display', toBoolean(this.$eval(expression)) ? 'none' : '');
}, element);
};
});
angularDirective("ng-style", function(expression, element){
return function(element){
this.$onEval(function(){
element.css(this.$eval(expression));
}, element);
};
});

298
src/filters.js Normal file
View file

@ -0,0 +1,298 @@
var angularFilterGoogleChartApi;
foreach({
'currency': function(amount){
this.$element.toggleClass('ng-format-negative', amount < 0);
return '$' + angularFilter['number'].apply(this, [amount, 2]);
},
'number': function(amount, fractionSize){
if (isNaN(amount) || !isFinite(amount)) {
return '';
}
fractionSize = typeof fractionSize == 'undefined' ? 2 : fractionSize;
var isNegative = amount < 0;
amount = Math.abs(amount);
var pow = Math.pow(10, fractionSize);
var text = "" + Math.round(amount * pow);
var whole = text.substring(0, text.length - fractionSize);
whole = whole || '0';
var frc = text.substring(text.length - fractionSize);
text = isNegative ? '-' : '';
for (var i = 0; i < whole.length; i++) {
if ((whole.length - i)%3 === 0 && i !== 0) {
text += ',';
}
text += whole.charAt(i);
}
if (fractionSize > 0) {
for (var j = frc.length; j < fractionSize; j++) {
frc += '0';
}
text += '.' + frc.substring(0, fractionSize);
}
return text;
},
'date': function(amount) {
},
'json': function(object) {
this.$element.addClass("ng-monospace");
return toJson(object, true);
},
'trackPackage': (function(){
var MATCHERS = [
{ name: "UPS",
url: "http://wwwapps.ups.com/WebTracking/processInputRequest?sort_by=status&tracknums_displayed=1&TypeOfInquiryNumber=T&loc=en_US&track.x=0&track.y=0&InquiryNumber1=",
regexp: [
/^1Z[0-9A-Z]{16}$/i]},
{ name: "FedEx",
url: "http://www.fedex.com/Tracking?tracknumbers=",
regexp: [
/^96\d{10}?$/i,
/^96\d{17}?$/i,
/^96\d{20}?$/i,
/^\d{15}$/i,
/^\d{12}$/i]},
{ name: "USPS",
url: "http://trkcnfrm1.smi.usps.com/PTSInternetWeb/InterLabelInquiry.do?origTrackNum=",
regexp: [
/^(91\d{20})$/i,
/^(91\d{18})$/i]}];
return function(trackingNo, noMatch) {
trackingNo = trim(trackingNo);
var tNo = trackingNo.replace(/ /g, '');
var returnValue;
foreach(MATCHERS, function(carrier){
foreach(carrier.regexp, function(regexp){
if (!returnValue && regexp.test(tNo)) {
var text = carrier.name + ": " + trackingNo;
var url = carrier.url + trackingNo;
returnValue = jqLite('<a></a>');
returnValue.text(text);
returnValue.attr('href', url);
}
});
});
if (returnValue)
return returnValue;
else if (trackingNo)
return noMatch || trackingNo + " is not recognized";
else
return null;
};})(),
'link': function(obj, title) {
if (obj) {
var text = title || obj.text || obj;
var url = obj.url || obj;
if (url) {
if (angular.validator.email(url) === null) {
url = "mailto:" + url;
}
var a = jqLite('<a></a>');
a.attr('href', url);
a.text(text);
return a;
}
}
return obj;
},
'bytes': (function(){
var SUFFIX = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
return function(size) {
if(size === null) return "";
var suffix = 0;
while (size > 1000) {
size = size / 1024;
suffix++;
}
var txt = "" + size;
var dot = txt.indexOf('.');
if (dot > -1 && dot + 2 < txt.length) {
txt = txt.substring(0, dot + 2);
}
return txt + " " + SUFFIX[suffix];
};
})(),
'image': function(obj, width, height) {
if (obj && obj.url) {
var style = "", img = jqLite('<img>');
if (width) {
img.css('max-width', width + 'px');
img.css('max-height', (height || width) + 'px');
}
img.attr('src', obj.url);
return img;
}
return null;
},
'lowercase': lowercase,
'uppercase': uppercase,
'linecount': function (obj) {
if (isString(obj)) {
if (obj==='') return 1;
return obj.split(/\n|\f/).length;
}
return 1;
},
'if': function (result, expression) {
return expression ? result : undefined;
},
'unless': function (result, expression) {
return expression ? undefined : result;
},
'googleChartApi': extend(
function(type, data, width, height) {
data = data || {};
var chart = {
'cht':type,
'chco':angularFilterGoogleChartApi['collect'](data, 'color'),
'chtt':angularFilterGoogleChartApi['title'](data),
'chdl':angularFilterGoogleChartApi['collect'](data, 'label'),
'chd':angularFilterGoogleChartApi['values'](data),
'chf':'bg,s,FFFFFF00'
};
if (_.isArray(data['xLabels'])) {
chart['chxt']='x';
chart['chxl']='0:|' + data.xLabels.join('|');
}
return angularFilterGoogleChartApi['encode'](chart, width, height);
},
{
'values': function(data){
var seriesValues = [];
foreach(data['series']||[], function(serie){
var values = [];
foreach(serie['values']||[], function(value){
values.push(value);
});
seriesValues.push(values.join(','));
});
var values = seriesValues.join('|');
return values === "" ? null : "t:" + values;
},
'title': function(data){
var titles = [];
var title = data['title'] || [];
foreach(_.isArray(title)?title:[title], function(text){
titles.push(encodeURIComponent(text));
});
return titles.join('|');
},
'collect': function(data, key){
var outterValues = [];
var count = 0;
foreach(data['series']||[], function(serie){
var innerValues = [];
var value = serie[key] || [];
foreach(_.isArray(value)?value:[value], function(color){
innerValues.push(encodeURIComponent(color));
count++;
});
outterValues.push(innerValues.join('|'));
});
return count?outterValues.join(','):null;
},
'encode': function(params, width, height) {
width = width || 200;
height = height || width;
var url = "http://chart.apis.google.com/chart?",
urlParam = [],
img = jqLite('<img>');
params['chs'] = width + "x" + height;
foreach(params, function(value, key){
if (value) {
urlParam.push(key + "=" + value);
}
});
urlParam.sort();
url += urlParam.join("&");
img.attr('src', url);
img.css({width: width + 'px', height: height + 'px'});
return img;
}
}
),
'qrcode': function(value, width, height) {
return angularFilterGoogleChartApi['encode']({
'cht':'qr', 'chl':encodeURIComponent(value)}, width, height);
},
'chart': {
'pie':function(data, width, height) {
return angularFilterGoogleChartApi('p', data, width, height);
},
'pie3d':function(data, width, height) {
return angularFilterGoogleChartApi('p3', data, width, height);
},
'pieConcentric':function(data, width, height) {
return angularFilterGoogleChartApi('pc', data, width, height);
},
'barHorizontalStacked':function(data, width, height) {
return angularFilterGoogleChartApi('bhs', data, width, height);
},
'barHorizontalGrouped':function(data, width, height) {
return angularFilterGoogleChartApi('bhg', data, width, height);
},
'barVerticalStacked':function(data, width, height) {
return angularFilterGoogleChartApi('bvs', data, width, height);
},
'barVerticalGrouped':function(data, width, height) {
return angularFilterGoogleChartApi('bvg', data, width, height);
},
'line':function(data, width, height) {
return angularFilterGoogleChartApi('lc', data, width, height);
},
'sparkline':function(data, width, height) {
return angularFilterGoogleChartApi('ls', data, width, height);
},
'scatter':function(data, width, height) {
return angularFilterGoogleChartApi('s', data, width, height);
}
},
'html': function(html){
return new HTML(html);
},
'linky': function(text){
if (!text) return text;
function regExpEscape(text) {
return text.replace(/([\/\.\*\+\?\|\(\)\[\]\{\}\\])/g, '\\$1');
}
var URL = /(ftp|http|https|mailto):\/\/([^\(\)|\s]+)/;
var match;
var raw = text;
var html = [];
while (match=raw.match(URL)) {
var url = match[0].replace(/[\.\;\,\(\)\{\}\<\>]$/,'');
var i = raw.indexOf(url);
html.push(escapeHtml(raw.substr(0, i)));
html.push('<a href="' + url + '">');
html.push(url);
html.push('</a>');
raw = raw.substring(i + url.length);
}
html.push(escapeHtml(raw));
return new HTML(html.join(''));
}
}, function(v,k){angularFilter[k] = v;});
angularFilterGoogleChartApi = angularFilter['googleChartApi'];

32
src/formatters.js Normal file
View file

@ -0,0 +1,32 @@
function formatter(format, parse) {return {'format':format, 'parse':parse || format};}
function toString(obj) {return (isDefined(obj) && obj !== null) ? "" + obj : obj;}
var NUMBER = /^\s*[-+]?\d*(\.\d*)?\s*$/;
extend(angularFormatter, {
'noop':formatter(identity, identity),
'boolean':formatter(toString, toBoolean),
'number':formatter(toString,
function(obj){
if (isString(obj) && NUMBER.exec(obj)) {
return obj ? 1*obj : null;
}
throw "Not a number";
}),
'list':formatter(
function(obj) { return obj ? obj.join(", ") : obj; },
function(value) {
var list = [];
foreach((value || '').split(','), function(item){
item = trim(item);
if (item) list.push(item);
});
return list;
}
),
'trim':formatter(
function(obj) { return obj ? trim("" + obj) : ""; }
)
});

248
src/jqLite.js Normal file
View file

@ -0,0 +1,248 @@
//////////////////////////////////
//JQLite
//////////////////////////////////
var jqCache = {};
var jqName = 'ng-' + new Date().getTime();
var jqId = 1;
function jqNextId() { return (jqId++); }
var addEventListener = window.document.attachEvent ?
function(element, type, fn) {
element.attachEvent('on' + type, fn);
} : function(element, type, fn) {
element.addEventListener(type, fn, false);
};
var removeEventListener = window.document.detachEvent ?
function(element, type, fn) {
element.detachEvent('on' + type, fn);
} : function(element, type, fn) {
element.removeEventListener(type, fn, false);
};
function jqClearData(element) {
var cacheId = element[jqName],
cache = jqCache[cacheId];
if (cache) {
foreach(cache.bind || {}, function(fn, type){
removeEventListener(element, type, fn);
});
delete jqCache[cacheId];
if (msie)
element[jqName] = ''; // ie does not allow deletion of attributes on elements.
else
delete element[jqName];
}
}
function JQLite(element) {
if (isElement(element)) {
this[0] = element;
this.length = 1;
} else if (isDefined(element.length) && element.item) {
for(var i=0; i < element.length; i++) {
this[i] = element[i];
}
this.length = element.length;
}
}
JQLite.prototype = {
data: function(key, value) {
var element = this[0],
cacheId = element[jqName],
cache = jqCache[cacheId || -1];
if (isDefined(value)) {
if (!cache) {
element[jqName] = cacheId = jqNextId();
cache = jqCache[cacheId] = {};
}
cache[key] = value;
} else {
return cache ? cache[key] : null;
}
},
removeData: function(){
jqClearData(this[0]);
},
dealoc: function(){
(function dealoc(element){
jqClearData(element);
for ( var i = 0, children = element.childNodes; i < children.length; i++) {
dealoc(children[i]);
}
})(this[0]);
},
bind: function(type, fn){
var self = this,
element = self[0],
bind = self.data('bind'),
eventHandler;
if (!bind) this.data('bind', bind = {});
foreach(type.split(' '), function(type){
eventHandler = bind[type];
if (!eventHandler) {
bind[type] = eventHandler = function(event) {
var bubbleEvent = false;
foreach(eventHandler.fns, function(fn){
bubbleEvent = bubbleEvent || fn.call(self, event);
});
if (!bubbleEvent) {
if (msie) {
event.returnValue = false;
event.cancelBubble = true;
} else {
event.preventDefault();
event.stopPropagation();
}
}
};
eventHandler.fns = [];
addEventListener(element, type, eventHandler);
}
eventHandler.fns.push(fn);
});
},
trigger: function(type) {
var evnt = document.createEvent('MouseEvent');
evnt.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
this[0].dispatchEvent(evnt);
},
replaceWith: function(replaceNode) {
this[0].parentNode.replaceChild(jqLite(replaceNode)[0], this[0]);
},
children: function() {
return new JQLite(this[0].childNodes);
},
append: function(node) {
var self = this[0];
node = jqLite(node);
foreach(node, function(child){
self.appendChild(child);
});
},
remove: function() {
this.dealoc();
var parentNode = this[0].parentNode;
if (parentNode) parentNode.removeChild(this[0]);
},
removeAttr: function(name) {
this[0].removeAttribute(name);
},
after: function(element) {
this[0].parentNode.insertBefore(jqLite(element)[0], this[0].nextSibling);
},
hasClass: function(selector) {
var className = " " + selector + " ";
if ( (" " + this[0].className + " ").replace(/[\n\t]/g, " ").indexOf( className ) > -1 ) {
return true;
}
return false;
},
removeClass: function(selector) {
this[0].className = trim((" " + this[0].className + " ").replace(/[\n\t]/g, " ").replace(" " + selector + " ", ""));
},
toggleClass: function(selector, condition) {
var self = this;
(condition ? self.addClass : self.removeClass).call(self, selector);
},
addClass: function( selector ) {
if (!this.hasClass(selector)) {
this[0].className = trim(this[0].className + ' ' + selector);
}
},
css: function(name, value) {
var style = this[0].style;
if (isString(name)) {
if (isDefined(value)) {
style[name] = value;
} else {
return style[name];
}
} else {
extend(style, name);
}
},
attr: function(name, value){
var e = this[0];
if (isObject(name)) {
foreach(name, function(value, name){
e.setAttribute(name, value);
});
} else if (isDefined(value)) {
e.setAttribute(name, value);
} else {
var attributes = e.attributes,
item = attributes ? attributes.getNamedItem(name) : undefined;
return item && item.specified ? item.value : undefined;
}
},
text: function(value) {
if (isDefined(value)) {
this[0].textContent = value;
}
return this[0].textContent;
},
val: function(value) {
if (isDefined(value)) {
this[0].value = value;
}
return this[0].value;
},
html: function(value) {
if (isDefined(value)) {
var i = 0, childNodes = this[0].childNodes;
for ( ; i < childNodes.length; i++) {
jqLite(childNodes[i]).dealoc();
}
this[0].innerHTML = value;
}
return this[0].innerHTML;
},
parent: function() {
return jqLite(this[0].parentNode);
},
clone: function() { return jqLite(this[0].cloneNode(true)); }
};
if (msie) {
extend(JQLite.prototype, {
text: function(value) {
var e = this[0];
// NodeType == 3 is text node
if (e.nodeType == 3) {
if (isDefined(value)) e.nodeValue = value;
return e.nodeValue;
} else {
if (isDefined(value)) e.innerText = value;
return e.innerText;
}
},
trigger: function(type) {
this[0].fireEvent('on' + type);
}
});
}

85
src/markups.js Normal file
View file

@ -0,0 +1,85 @@
function parseBindings(string) {
var results = [];
var lastIndex = 0;
var index;
while((index = string.indexOf('{{', lastIndex)) > -1) {
if (lastIndex < index)
results.push(string.substr(lastIndex, index - lastIndex));
lastIndex = index;
index = string.indexOf('}}', index);
index = index < 0 ? string.length : index + 2;
results.push(string.substr(lastIndex, index - lastIndex));
lastIndex = index;
}
if (lastIndex != string.length)
results.push(string.substr(lastIndex, string.length - lastIndex));
return results.length === 0 ? [ string ] : results;
}
function binding(string) {
var binding = string.replace(/\n/gm, ' ').match(/^\{\{(.*)\}\}$/);
return binding ? binding[1] : null;
}
function hasBindings(bindings) {
return bindings.length > 1 || binding(bindings[0]) !== null;
}
angularTextMarkup('{{}}', function(text, textNode, parentElement) {
var bindings = parseBindings(text),
self = this;
if (hasBindings(bindings)) {
if (isLeafNode(parentElement[0])) {
parentElement.attr('ng-bind-template', text);
} else {
var cursor = textNode, newElement;
foreach(parseBindings(text), function(text){
var exp = binding(text);
if (exp) {
newElement = self.element('span');
newElement.attr('ng-bind', exp);
} else {
newElement = self.text(text);
}
if (msie && text.charAt(0) == ' ') {
newElement = jqLite('<span>&nbsp;</span>');
var nbsp = newElement.html();
newElement.text(text.substr(1));
newElement.html(nbsp + newElement.html());
}
cursor.after(newElement);
cursor = newElement;
});
}
textNode.remove();
}
});
// TODO: this should be widget not a markup
angularTextMarkup('OPTION', function(text, textNode, parentElement){
if (nodeName(parentElement) == "OPTION") {
var select = document.createElement('select');
select.insertBefore(parentElement[0].cloneNode(true), null);
if (!select.innerHTML.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) {
parentElement.attr('value', text);
}
}
});
var NG_BIND_ATTR = 'ng-bind-attr';
angularAttrMarkup('{{}}', function(value, name, element){
if (name.substr(0, 3) != 'ng-') {
if (msie && name == 'src')
value = decodeURI(value);
var bindings = parseBindings(value),
bindAttr;
if (hasBindings(bindings)) {
element.removeAttr(name);
bindAttr = fromJson(element.attr(NG_BIND_ATTR) || "{}");
bindAttr[name] = value;
element.attr(NG_BIND_ATTR, toJson(bindAttr));
}
}
});

View file

@ -0,0 +1,72 @@
function ControlBar(document, serverUrl, database) {
this._document = document;
this.serverUrl = serverUrl;
this.database = database;
this._window = window;
this.callbacks = [];
};
ControlBar.HTML =
'<div>' +
'<div class="ui-widget-overlay"></div>' +
'<div id="ng-login" ng-non-bindable="true">' +
'<div class="ng-login-container"></div>' +
'</div>' +
'</div>';
ControlBar.FORBIDEN =
'<div ng-non-bindable="true" title="Permission Error:">' +
'Sorry, you do not have permission for this!'+
'</div>';
ControlBar.prototype = {
bind: function () {
},
login: function (loginSubmitFn) {
this.callbacks.push(loginSubmitFn);
if (this.callbacks.length == 1) {
this.doTemplate("/user_session/new.mini?database="+encodeURIComponent(this.database)+"&return_url=" + encodeURIComponent(this.urlWithoutAnchor()));
}
},
logout: function (loginSubmitFn) {
this.callbacks.push(loginSubmitFn);
if (this.callbacks.length == 1) {
this.doTemplate("/user_session/do_destroy.mini");
}
},
urlWithoutAnchor: function (path) {
return this._window['location']['href'].split("#")[0];
},
doTemplate: function (path) {
var self = this;
var id = new Date().getTime();
var url = this.urlWithoutAnchor() + "#$iframe_notify=" + id;
var iframeHeight = 330;
var loginView = jQuery('<div style="overflow:hidden; padding:2px 0 0 0;"><iframe name="'+ url +'" src="'+this.serverUrl + path + '" width="500" height="'+ iframeHeight +'"/></div>');
this._document.append(loginView);
loginView['dialog']({
'height':iframeHeight + 33, 'width':500,
'resizable': false, 'modal':true,
'title': 'Authentication: <a href="http://www.getangular.com"><tt>&lt;angular/&gt;</tt></a>'
});
angularCallbacks["_iframe_notify_" + id] = function() {
loginView['dialog']("destroy");
loginView['remove']();
foreach(self.callbacks, function(callback){
callback();
});
self.callbacks = [];
};
},
notAuthorized: function () {
if (this.forbidenView) return;
this.forbidenView = jQuery(ControlBar.FORBIDEN);
this.forbidenView.dialog({bgiframe:true, height:70, modal:true});
}
};

View file

@ -0,0 +1,330 @@
function DataStore(post, users, anchor) {
this.post = post;
this.users = users;
this._cache_collections = [];
this._cache = {'$collections':this._cache_collections};
this.anchor = anchor;
this.bulkRequest = [];
};
DataStore.NullEntity = extend(function(){}, {
'all': function(){return [];},
'query': function(){return [];},
'load': function(){return {};},
'title': undefined
});
DataStore.prototype = {
cache: function(document) {
if (! document.datastore === this) {
throw "Parameter must be an instance of Entity! " + toJson(document);
}
var key = document['$entity'] + '/' + document['$id'];
var cachedDocument = this._cache[key];
if (cachedDocument) {
Model.copyDirectFields(document, cachedDocument);
} else {
this._cache[key] = document;
cachedDocument = document;
}
return cachedDocument;
},
load: function(instance, id, callback, failure) {
if (id && id !== '*') {
var self = this;
this._jsonRequest(["GET", instance['$entity'] + "/" + id], function(response) {
instance['$loadFrom'](response);
instance['$migrate']();
var clone = instance['$$entity'](instance);
self.cache(clone);
(callback||noop)(instance);
}, failure);
}
return instance;
},
loadMany: function(entity, ids, callback) {
var self=this;
var list = [];
var callbackCount = 0;
foreach(ids, function(id){
list.push(self.load(entity(), id, function(){
callbackCount++;
if (callbackCount == ids.length) {
(callback||noop)(list);
}
}));
});
return list;
},
loadOrCreate: function(instance, id, callback) {
var self=this;
return this.load(instance, id, callback, function(response){
if (response['$status_code'] == 404) {
instance['$id'] = id;
(callback||noop)(instance);
} else {
throw response;
}
});
},
loadAll: function(entity, callback) {
var self = this;
var list = [];
list['$$accept'] = function(doc){
return doc['$entity'] == entity['title'];
};
this._cache_collections.push(list);
this._jsonRequest(["GET", entity['title']], function(response) {
var rows = response;
for ( var i = 0; i < rows.length; i++) {
var document = entity();
document['$loadFrom'](rows[i]);
list.push(self.cache(document));
}
(callback||noop)(list);
});
return list;
},
save: function(document, callback) {
var self = this;
var data = {};
document['$saveTo'](data);
this._jsonRequest(["POST", "", data], function(response) {
document['$loadFrom'](response);
var cachedDoc = self.cache(document);
_.each(self._cache_collections, function(collection){
if (collection['$$accept'](document)) {
angularArray['includeIf'](collection, cachedDoc, true);
}
});
if (document['$$anchor']) {
self.anchor[document['$$anchor']] = document['$id'];
}
if (callback)
callback(document);
});
},
remove: function(document, callback) {
var self = this;
var data = {};
document['$saveTo'](data);
this._jsonRequest(["DELETE", "", data], function(response) {
delete self._cache[document['$entity'] + '/' + document['$id']];
_.each(self._cache_collections, function(collection){
for ( var i = 0; i < collection.length; i++) {
var item = collection[i];
if (item['$id'] == document['$id']) {
collection.splice(i, 1);
}
}
});
(callback||noop)(response);
});
},
_jsonRequest: function(request, callback, failure) {
request['$$callback'] = callback;
request['$$failure'] = failure||function(response){
throw response;
};
this.bulkRequest.push(request);
},
flush: function() {
if (this.bulkRequest.length === 0) return;
var self = this;
var bulkRequest = this.bulkRequest;
this.bulkRequest = [];
log('REQUEST:', bulkRequest);
function callback(code, bulkResponse){
log('RESPONSE[' + code + ']: ', bulkResponse);
if(bulkResponse['$status_code'] == 401) {
self.users['login'](function(){
self.post(bulkRequest, callback);
});
} else if(bulkResponse['$status_code']) {
alert(toJson(bulkResponse));
} else {
for ( var i = 0; i < bulkResponse.length; i++) {
var response = bulkResponse[i];
var request = bulkRequest[i];
var responseCode = response['$status_code'];
if(responseCode) {
if(responseCode == 403) {
self.users['notAuthorized']();
} else {
request['$$failure'](response);
}
} else {
request['$$callback'](response);
}
}
}
}
this.post(bulkRequest, callback);
},
saveScope: function(scope, callback) {
var saveCounter = 1;
function onSaveDone() {
saveCounter--;
if (saveCounter === 0 && callback)
callback();
}
for(var key in scope) {
var item = scope[key];
if (item && item['$save'] == Model.prototype['$save']) {
saveCounter++;
item['$save'](onSaveDone);
}
}
onSaveDone();
},
query: function(type, query, arg, callback){
var self = this;
var queryList = [];
queryList['$$accept'] = function(doc){
return false;
};
this._cache_collections.push(queryList);
var request = type['title'] + '/' + query + '=' + arg;
this._jsonRequest(["GET", request], function(response){
var list = response;
foreach(list, function(item){
var document = type()['$loadFrom'](item);
queryList.push(self.cache(document));
});
(callback||noop)(queryList);
});
return queryList;
},
entities: function(callback) {
var entities = [];
var self = this;
this._jsonRequest(["GET", "$entities"], function(response) {
foreach(response, function(value, entityName){
entities.push(self.entity(entityName));
});
entities.sort(function(a,b){return a.title > b.title ? 1 : -1;});
(callback||noop)(entities);
});
return entities;
},
documentCountsByUser: function(){
var counts = {};
var self = this;
self.post([["GET", "$users"]], function(code, response){
extend(counts, response[0]);
});
return counts;
},
userDocumentIdsByEntity: function(user){
var ids = {};
var self = this;
self.post([["GET", "$users/" + user]], function(code, response){
extend(ids, response[0]);
});
return ids;
},
entity: function(name, defaults){
if (!name) {
return DataStore.NullEntity;
}
var self = this;
var entity = extend(function(initialState){
return new Model(entity, initialState);
}, {
// entity.name does not work as name seems to be reserved for functions
'title': name,
'$$factory': true,
datastore: this, //private, obfuscate
'defaults': defaults || {},
'load': function(id, callback){
return self.load(entity(), id, callback);
},
'loadMany': function(ids, callback){
return self.loadMany(entity, ids, callback);
},
'loadOrCreate': function(id, callback){
return self.loadOrCreate(entity(), id, callback);
},
'all': function(callback){
return self.loadAll(entity, callback);
},
'query': function(query, queryArgs, callback){
return self.query(entity, query, queryArgs, callback);
},
'properties': function(callback) {
self._jsonRequest(["GET", name + "/$properties"], callback);
}
});
return entity;
},
join: function(join){
function fn(){
throw "Joined entities can not be instantiated into a document.";
};
function base(name){return name ? name.substring(0, name.indexOf('.')) : undefined;}
function next(name){return name.substring(name.indexOf('.') + 1);}
var joinOrder = _(join).chain().
map(function($, name){
return name;}).
sortBy(function(name){
var path = [];
do {
if (_(path).include(name)) throw "Infinite loop in join: " + path.join(" -> ");
path.push(name);
if (!join[name]) throw _("Named entity '<%=name%>' is undefined.").template({name:name});
name = base(join[name].on);
} while(name);
return path.length;
}).
value();
if (_(joinOrder).select(function($){return join[$].on;}).length != joinOrder.length - 1)
throw "Exactly one entity needs to be primary.";
fn['query'] = function(exp, value) {
var joinedResult = [];
var baseName = base(exp);
if (baseName != joinOrder[0]) throw _("Named entity '<%=name%>' is not a primary entity.").template({name:baseName});
var Entity = join[baseName].join;
var joinIndex = 1;
Entity['query'](next(exp), value, function(result){
var nextJoinName = joinOrder[joinIndex++];
var nextJoin = join[nextJoinName];
var nextJoinOn = nextJoin.on;
var joinIds = {};
_(result).each(function(doc){
var row = {};
joinedResult.push(row);
row[baseName] = doc;
var id = Scope.getter(row, nextJoinOn);
joinIds[id] = id;
});
nextJoin.join.loadMany(_.toArray(joinIds), function(result){
var byId = {};
_(result).each(function(doc){
byId[doc.$id] = doc;
});
_(joinedResult).each(function(row){
var id = Scope.getter(row, nextJoinOn);
row[nextJoinName] = byId[id];
});
});
});
return joinedResult;
};
return fn;
}
};

View file

@ -0,0 +1,68 @@
function Server(url, getScript) {
this.url = url;
this.nextId = 0;
this.getScript = getScript;
this.uuid = "_" + ("" + Math.random()).substr(2) + "_";
this.maxSize = 1800;
};
Server.prototype = {
base64url: function(txt) {
return Base64.encode(txt);
},
request: function(method, url, request, callback) {
var requestId = this.uuid + (this.nextId++);
var payload = this.base64url(toJson({'u':url, 'm':method, 'p':request}));
var totalPockets = Math.ceil(payload.length / this.maxSize);
var baseUrl = this.url + "/$/" + requestId + "/" + totalPockets + "/";
angularCallbacks[requestId] = function(response) {
delete angularCallbacks[requestId];
callback(200, response);
};
for ( var pocketNo = 0; pocketNo < totalPockets; pocketNo++) {
var pocket = payload.substr(pocketNo * this.maxSize, this.maxSize);
this.getScript(baseUrl + (pocketNo+1) + "?h=" + pocket, noop);
}
}
};
function FrameServer(frame) {
this.frame = frame;
};
FrameServer.PREFIX = "$DATASET:";
FrameServer.prototype = {
read:function(){
this.data = fromJson(this.frame.name.substr(FrameServer.PREFIX.length));
},
write:function(){
this.frame.name = FrameServer.PREFIX + toJson(this.data);
},
request: function(method, url, request, callback) {
//alert(method + " " + url + " " + toJson(request) + " " + toJson(callback));
}
};
function VisualServer(delegate, status, update) {
this.delegate = delegate;
this.update = update;
this.status = status;
};
VisualServer.prototype = {
request:function(method, url, request, callback) {
var self = this;
this.status.beginRequest(request);
this.delegate.request(method, url, request, function() {
self.status.endRequest();
try {
callback.apply(this, arguments);
} catch (e) {
alert(toJson(e));
}
self.update();
});
}
};

View file

@ -0,0 +1,35 @@
function Users(server, controlBar) {
this.server = server;
this.controlBar = controlBar;
};
extend(Users.prototype, {
'fetchCurrentUser':function(callback) {
var self = this;
this.server.request("GET", "/account.json", {}, function(code, response){
self['current'] = response['user'];
callback(response['user']);
});
},
'logout': function(callback) {
var self = this;
this.controlBar.logout(function(){
delete self['current'];
(callback||noop)();
});
},
'login': function(callback) {
var self = this;
this.controlBar.login(function(){
self['fetchCurrentUser'](function(){
(callback||noop)();
});
});
},
'notAuthorized': function(){
this.controlBar.notAuthorized();
}
});

View file

@ -0,0 +1,29 @@
angular.directive("auth", function(expression, element){
return function(){
if(expression == "eager") {
this.$users.fetchCurrent();
}
};
});
//expression = "book=Book:{year=2000}"
angular.directive("entity", function(expression, element){
//parse expression, ignore element
var entityName; // "Book";
var instanceName; // "book";
var defaults; // {year: 2000};
parse(expression);
return function(){
this[entityName] = this.$datastore.entity(entityName, defaults);
this[instanceName] = this[entityName]();
this.$watch("$anchor."+instanceName, function(newAnchor){
this[instanceName] = this[entityName].get(this.$anchor[instanceName]);
});
};
});

63
src/scenario/DSL.js Normal file
View file

@ -0,0 +1,63 @@
angular.scenario.dsl.browser = {
navigateTo: function(url){
$scenario.addStep('Navigate to: ' + url, function(done){
var self = this;
this.testFrame.load(function(){
self.testFrame.unbind();
self.testWindow = self.testFrame[0].contentWindow;
self.testDocument = jQuery(self.testWindow.document);
self.$browser = self.testWindow.angular.service.$browser();
self.notifyWhenNoOutstandingRequests = bind(self.$browser, self.$browser.notifyWhenNoOutstandingRequests);
self.notifyWhenNoOutstandingRequests(done);
});
if (this.testFrame.attr('src') == url) {
this.testFrame[0].contentWindow.location.reload();
} else {
this.testFrame.attr('src', url);
}
});
}
};
angular.scenario.dsl.input = function(selector) {
return {
enter: function(value){
$scenario.addStep("Set input text of '" + selector + "' to '" +
value + "'", function(done){
var input = this.testDocument.find('input[name=' + selector + ']');
input.val(value);
this.testWindow.angular.element(input[0]).trigger('change');
done();
});
},
select: function(value){
$scenario.addStep("Select radio '" + selector + "' to '" +
value + "'", function(done){
var input = this.testDocument.
find(':radio[name$=@' + selector + '][value=' + value + ']');
var event = this.testWindow.document.createEvent('MouseEvent');
event.initMouseEvent('click', true, true, this.testWindow, 0,0,0,0,0, false, false, false, false, 0, null);
input[0].dispatchEvent(event);
done();
});
}
};
};
angular.scenario.dsl.expect = {
repeater: function(selector) {
return {
count: {
toEqual: function(number) {
$scenario.addStep("Expect that there are " + number + " items in Repeater with selector '" + selector + "'", function(done) {
var items = this.testDocument.find(selector);
if (items.length != number) {
this.result.fail("Expected " + number + " but was " + items.length);
}
done();
});
}
}
};
}
};

161
src/scenario/Runner.js Normal file
View file

@ -0,0 +1,161 @@
angular['scenario'] = angular['scenario'] || (angular['scenario'] = {});
angular.scenario['dsl'] = angular.scenario['dsl'] || (angular.scenario['dsl'] = {});
angular.scenario.Runner = function(scope, jQuery){
var self = scope.$scenario = this;
this.scope = scope;
this.jQuery = jQuery;
var specs = this.specs = {};
var path = [];
this.scope.describe = function(name, body){
path.push(name);
body();
path.pop();
};
var beforeEach = noop;
var afterEach = noop;
this.scope.beforeEach = function(body) {
beforeEach = body;
};
this.scope.afterEach = function(body) {
afterEach = body;
};
this.scope.it = function(name, body) {
var specName = path.join(' ') + ': it ' + name;
self.currentSpec = specs[specName] = {
name: specName,
steps:[]
};
try {
beforeEach();
body();
} catch(err) {
self.addStep(err.message || 'ERROR', function(){
throw err;
});
} finally {
afterEach();
}
self.currentSpec = null;
};
this.logger = function returnNoop(){
return extend(returnNoop, {close:noop, fail:noop});;
};
};
angular.scenario.Runner.prototype = {
run: function(body){
var jQuery = this.jQuery;
body.append(
'<div id="runner">' +
'<div class="console"></div>' +
'</div>' +
'<div id="testView">' +
'<iframe></iframe>' +
'</div>');
var console = body.find('#runner .console');
console.find('li').live('click', function(){
jQuery(this).toggleClass('collapsed');
});
this.testFrame = body.find('#testView iframe');
function logger(parent) {
var container;
return function(type, text) {
if (!container) {
container = jQuery('<ul></ul>');
parent.append(container);
}
var element = jQuery('<li class="running '+type+'"><span></span></li>');
element.find('span').text(text);
container.append(element);
return extend(logger(element), {
close: function(){
element.removeClass('running');
if(!element.hasClass('fail'))
element.addClass('collapsed');
console.scrollTop(console[0].scrollHeight);
},
fail: function(){
element.removeClass('running');
var current = element;
while (current[0] != console[0]) {
if (current.is('li'))
current.addClass('fail');
current = current.parent();
}
}
});
};
}
this.logger = logger(console);
var specNames = [];
foreach(this.specs, function(spec, name){
specNames.push(name);
}, this);
specNames.sort();
var self = this;
function callback(){
var next = specNames.shift();
if(next) {
self.execute(next, callback);
}
};
callback();
},
addStep: function(name, step) {
this.currentSpec.steps.push({name:name, fn:step});
},
execute: function(name, callback) {
var spec = this.specs[name],
self = this,
result = {
passed: false,
failed: false,
finished: false,
fail: function(error) {
result.passed = false;
result.failed = true;
result.error = error;
result.log('fail', isString(error) ? error : toJson(error)).fail();
}
},
specThis = createScope({
result: result,
testFrame: this.testFrame,
testWindow: this.testWindow
}, angularService, {});
this.self = specThis;
var stepLogger = this.logger('spec', name);
spec.nextStepIndex = 0;
function done() {
result.finished = true;
stepLogger.close();
self.self = null;
(callback||noop).call(specThis);
}
function next(){
var step = spec.steps[spec.nextStepIndex];
(result.log || {close:noop}).close();
result.log = null;
if (step) {
spec.nextStepIndex ++;
result.log = stepLogger('step', step.name);
try {
step.fn.call(specThis, next);
} catch (e) {
console.error(e);
result.fail(e);
done();
}
} else {
result.passed = !result.failed;
done();
}
};
next();
return specThis;
}
};

View file

@ -0,0 +1,30 @@
/**
* The MIT License
*
* Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
(function(window, document, previousOnLoad){
window.angular = {
scenario: {
dsl: window
}
};

View file

@ -0,0 +1,11 @@
var $scenarioRunner = new angular.scenario.Runner(window, jQuery);
window.onload = function(){
try {
if (previousOnLoad) previousOnLoad();
} catch(e) {}
$scenarioRunner.run(jQuery(window.document.body));
};
})(window, document, window.onload);

Some files were not shown because too many files have changed in this diff Show more