Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
R
renderjs
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Xiaowu Zhang
renderjs
Commits
720d75aa
Commit
720d75aa
authored
Jan 31, 2013
by
Ivan Tyagov
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'GadgetCatalog'
parents
8650bed5
18958049
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
3962 additions
and
1 deletion
+3962
-1
lib/jio/davstorage.js
lib/jio/davstorage.js
+927
-0
lib/jio/jio.js
lib/jio/jio.js
+2509
-0
lib/jio/md5.js
lib/jio/md5.js
+379
-0
renderjs.js
renderjs.js
+83
-0
require-renderjs.js
require-renderjs.js
+4
-1
test/gadget_index/gadget_index.json
test/gadget_index/gadget_index.json
+11
-0
test/renderjs_test.js
test/renderjs_test.js
+49
-0
No files found.
lib/jio/davstorage.js
0 → 100644
View file @
720d75aa
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global jIO: true, $: true, btoa: true */
// test here: http://enable-cors.org/
//http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy
jIO
.
addStorageType
(
'
dav
'
,
function
(
spec
,
my
)
{
spec
=
spec
||
{};
var
that
,
priv
,
super_serialized
;
that
=
my
.
basicStorage
(
spec
,
my
);
priv
=
{};
super_serialized
=
that
.
serialized
;
priv
.
secureDocId
=
function
(
string
)
{
var
split
=
string
.
split
(
'
/
'
),
i
;
if
(
split
[
0
]
===
''
)
{
split
=
split
.
slice
(
1
);
}
for
(
i
=
0
;
i
<
split
.
length
;
i
+=
1
)
{
if
(
split
[
i
]
===
''
)
{
return
''
;
}
}
return
split
.
join
(
'
%2F
'
);
};
priv
.
convertSlashes
=
function
(
string
)
{
return
string
.
split
(
'
/
'
).
join
(
'
%2F
'
);
};
priv
.
restoreSlashes
=
function
(
string
)
{
return
string
.
split
(
'
%2F
'
).
join
(
'
/
'
);
};
/**
* Checks if an object has no enumerable keys
* @method objectIsEmpty
* @param {object} obj The object
* @return {boolean} true if empty, else false
*/
priv
.
objectIsEmpty
=
function
(
obj
)
{
var
k
;
for
(
k
in
obj
)
{
if
(
obj
.
hasOwnProperty
(
k
))
{
return
false
;
}
}
return
true
;
};
// ==================== Attributes ====================
priv
.
username
=
spec
.
username
||
''
;
priv
.
secured_username
=
priv
.
convertSlashes
(
priv
.
username
);
priv
.
password
=
spec
.
password
||
''
;
priv
.
url
=
spec
.
url
||
''
;
that
.
serialized
=
function
()
{
var
o
=
super_serialized
();
o
.
username
=
priv
.
username
;
o
.
url
=
priv
.
url
;
o
.
password
=
priv
.
password
;
return
o
;
};
priv
.
newAsyncModule
=
function
()
{
var
async
=
{};
async
.
call
=
function
(
obj
,
function_name
,
arglist
)
{
obj
.
_wait
=
obj
.
_wait
||
{};
if
(
obj
.
_wait
[
function_name
])
{
obj
.
_wait
[
function_name
]
-=
1
;
return
function
()
{};
}
// ok if undef or 0
arglist
=
arglist
||
[];
return
obj
[
function_name
].
apply
(
obj
[
function_name
],
arglist
);
};
async
.
neverCall
=
function
(
obj
,
function_name
)
{
obj
.
_wait
=
obj
.
_wait
||
{};
obj
.
_wait
[
function_name
]
=
-
1
;
};
async
.
wait
=
function
(
obj
,
function_name
,
times
)
{
obj
.
_wait
=
obj
.
_wait
||
{};
obj
.
_wait
[
function_name
]
=
times
;
};
async
.
end
=
function
()
{
async
.
call
=
function
()
{};
};
return
async
;
};
/**
* Checks if a browser supports cors (cross domain ajax requests)
* @method checkCors
* @return {boolean} true if supported, else false
*/
priv
.
checkCors
=
function
()
{
return
$
.
support
.
cors
;
};
/**
* Replaces last "." with "_." in document filenames
* @method underscoreFileExtenisons
* @param {string} url url to clean up
* @return {string} clean_url cleaned up URL
*/
priv
.
underscoreFileExtenisons
=
function
(
url
)
{
var
clean_url
=
url
.
replace
(
/,
\s(\w
+
)
$/
,
"
_.$1
"
);
return
clean_url
;
};
priv
.
restoreDots
=
function
(
url
)
{
var
clean_url
=
url
.
replace
(
/_
\.
/g
,
'
.
'
);
return
clean_url
;
};
// wedDav methods rfc4918 (short summary)
// COPY Reproduces single resources (files) and collections (directory
// trees). Will overwrite files (if specified by request) but will
// respond 209 (Conflict) if it would overwrite a tree
// DELETE deletes files and directory trees
// GET just the vanilla HTTP/1.1 behaviour
// HEAD ditto
// LOCK locks a resources
// MKCOL creates a directory
// MOVE Moves (rename or copy) a file or a directory tree. Will
// 'overwrite' files (if specified by the request) but will respond
// 209 (Conflict) if it would overwrite a tree.
// OPTIONS If WebDAV is enabled and available for the path this reports the
// WebDAV extension methods
// PROPFIND Retrieves the requested file characteristics, DAV lock status
// and 'dead' properties for individual files, a directory and its
// child files, or a directory tree
// PROPPATCHset and remove 'dead' meta-data properties
// PUT Update or create resource or collections
// UNLOCK unlocks a resource
// Notes: all Ajax requests should be CORS (cross-domain)
// adding custom headers triggers preflight OPTIONS request!
// http://remysharp.com/2011/04/21/getting-cors-working/
priv
.
putOrPost
=
function
(
command
,
type
)
{
var
docid
=
command
.
getDocId
(),
secured_docid
,
url
;
// no docId
if
(
!
(
typeof
docid
===
"
string
"
&&
docid
!==
""
))
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Cannot create document which id is undefined
"
,
"
reason
"
:
"
Document id is undefined
"
});
return
;
}
// no cross domain ajax
if
(
priv
.
checkCors
===
false
)
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Browser does not support cross domain ajax requests
"
,
"
reason
"
:
"
cors is undefined
"
});
return
;
}
secured_docid
=
priv
.
secureDocId
(
command
.
getDocId
());
url
=
priv
.
url
+
'
/
'
+
priv
.
underscoreFileExtenisons
(
secured_docid
);
// see if the document exists
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
"
GET
"
,
async
:
true
,
dataType
:
'
text
'
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
// xhrFields: {withCredentials: 'true'},
success
:
function
()
{
if
(
type
===
'
POST
'
)
{
// POST the document already exists
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflicts
"
,
"
error
"
:
"
conflicts
"
,
"
message
"
:
"
Cannot create a new document
"
,
"
reason
"
:
"
Document already exists
"
});
return
;
}
// PUT update document
$
.
ajax
({
url
:
url
,
type
:
type
,
data
:
JSON
.
stringify
(
command
.
getDoc
()),
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
// xhrFields: {withCredentials: 'true'},
success
:
function
()
{
that
.
success
({
ok
:
true
,
id
:
command
.
getDocId
()
});
},
error
:
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflicts
"
,
"
error
"
:
"
conflicts
"
,
"
message
"
:
"
Cannot modify document
"
,
"
reason
"
:
"
Error trying to write to remote storage
"
});
}
});
},
error
:
function
(
err
)
{
// Firefox returns 0 instead of 404 on CORS?
if
(
err
.
status
===
404
||
err
.
status
===
0
)
{
$
.
ajax
({
url
:
url
,
type
:
'
PUT
'
,
data
:
JSON
.
stringify
(
command
.
getDoc
()),
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
// xhrFields: {withCredentials: 'true'},
success
:
function
()
{
that
.
success
({
ok
:
true
,
id
:
command
.
getDocId
()
});
},
error
:
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflicts
"
,
"
error
"
:
"
conflicts
"
,
"
message
"
:
"
Cannot modify document
"
,
"
reason
"
:
"
Error trying to write to remote storage
"
});
}
});
}
else
{
// error accessing remote storage
that
.
error
({
"
status
"
:
err
.
status
,
"
statusText
"
:
err
.
statusText
,
"
error
"
:
"
error
"
,
"
message
"
:
err
.
message
,
"
reason
"
:
"
Failed to access remote storage
"
});
}
}
});
};
/**
* Creates a new document
* @method post
* @param {object} command The JIO command
*/
that
.
post
=
function
(
command
)
{
priv
.
putOrPost
(
command
,
'
POST
'
);
};
/**
* Creates or updates a document
* @method put
* @param {object} command The JIO command
*/
that
.
put
=
function
(
command
)
{
priv
.
putOrPost
(
command
,
'
PUT
'
);
};
/**
* Add an attachment to a document
* @method putAttachment
* @param {object} command The JIO command
*/
that
.
putAttachment
=
function
(
command
)
{
var
docid
=
command
.
getDocId
(),
doc
,
url
,
secured_docid
,
secured_attachmentid
,
attachment_url
;
// no docId
if
(
!
(
typeof
docid
===
"
string
"
&&
docid
!==
""
))
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Cannot create document which id is undefined
"
,
"
reason
"
:
"
Document id is undefined
"
});
return
;
}
// no cross domain ajax
if
(
priv
.
checkCors
===
false
)
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Browser does not support cross domain ajax requests
"
,
"
reason
"
:
"
cors is undefined
"
});
return
;
}
secured_docid
=
priv
.
secureDocId
(
docid
);
url
=
priv
.
url
+
'
/
'
+
priv
.
underscoreFileExtenisons
(
secured_docid
);
// see if the underlying document exists
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
GET
'
,
async
:
true
,
dataType
:
'
text
'
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
(
response
)
{
doc
=
JSON
.
parse
(
response
);
// the document exists - update document
doc
.
_attachments
=
doc
.
_attachments
||
{};
doc
.
_attachments
[
command
.
getAttachmentId
()]
=
{
"
content_type
"
:
command
.
getAttachmentMimeType
(),
"
digest
"
:
"
md5-
"
+
command
.
md5SumAttachmentData
(),
"
length
"
:
command
.
getAttachmentLength
()
};
// put updated document data
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
PUT
'
,
data
:
JSON
.
stringify
(
doc
),
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
// xhrFields: {withCredentials: 'true'},
success
:
function
()
{
secured_attachmentid
=
priv
.
secureDocId
(
command
.
getAttachmentId
());
attachment_url
=
url
+
'
.
'
+
priv
.
underscoreFileExtenisons
(
secured_attachmentid
);
$
.
ajax
({
url
:
attachment_url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
PUT
'
,
data
:
JSON
.
stringify
(
command
.
getDoc
()),
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
// xhrFields: {withCredentials: 'true'},
success
:
function
()
{
that
.
success
({
ok
:
true
,
id
:
command
.
getDocId
()
+
'
/
'
+
command
.
getAttachmentId
()
});
},
error
:
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflicts
"
,
"
error
"
:
"
conflicts
"
,
"
message
"
:
"
Cannot modify document
"
,
"
reason
"
:
"
Error trying to save attachment to remote storage
"
});
return
;
}
});
},
error
:
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflicts
"
,
"
error
"
:
"
conflicts
"
,
"
message
"
:
"
Cannot modify document
"
,
"
reason
"
:
"
Error trying to write to remote storage
"
});
return
;
}
});
},
error
:
function
()
{
// the document does not exist
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Impossible to add attachment
"
,
"
reason
"
:
"
Document not found
"
});
return
;
}
});
};
/**
* Get a document or attachment from distant storage
* Options:
* - {boolean} revs Add simple revision history (false by default).
* - {boolean} revs_info Add revs info (false by default).
* - {boolean} conflicts Add conflict object (false by default).
* @method get
* @param {object} command The JIO command
*/
that
.
get
=
function
(
command
)
{
var
docid
=
command
.
getDocId
(),
doc
,
url
,
secured_docid
,
secured_attachmentid
,
attachment_url
;
// no docId
if
(
!
(
typeof
docid
===
"
string
"
&&
docid
!==
""
))
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Cannot create document which id is undefined
"
,
"
reason
"
:
"
Document id is undefined
"
});
return
;
}
// no cors support
if
(
priv
.
checkCors
===
false
)
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Browser does not support cross domain ajax requests
"
,
"
reason
"
:
"
cors is undefined
"
});
return
;
}
secured_docid
=
priv
.
secureDocId
(
command
.
getDocId
());
url
=
priv
.
url
+
'
/
'
+
priv
.
underscoreFileExtenisons
(
secured_docid
);
if
(
typeof
command
.
getAttachmentId
()
===
"
string
"
)
{
secured_attachmentid
=
priv
.
secureDocId
(
command
.
getAttachmentId
());
attachment_url
=
url
+
'
.
'
+
priv
.
underscoreFileExtenisons
(
secured_attachmentid
);
// get attachment
$
.
ajax
({
url
:
attachment_url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
GET
'
,
async
:
true
,
dataType
:
'
text
'
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
(
response
)
{
doc
=
JSON
.
parse
(
response
);
that
.
success
(
doc
);
},
error
:
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the attachment
"
,
"
reason
"
:
"
Attachment does not exist
"
});
}
});
}
else
{
// get document
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
GET
'
,
async
:
true
,
dataType
:
'
text
'
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
(
response
)
{
// metadata_only should not be handled by jIO, as it is a
// webDav only option, shouldn't it?
// ditto for content_only
doc
=
JSON
.
parse
(
response
);
that
.
success
(
doc
);
},
error
:
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Document does not exist
"
});
}
});
}
};
/**
* Remove a document or attachment
* @method remove
* @param {object} command The JIO command
*/
that
.
remove
=
function
(
command
)
{
var
docid
=
command
.
getDocId
(),
doc
,
url
,
secured_docid
,
secured_attachmentid
,
attachment_url
,
attachment_list
=
[],
i
,
j
,
k
=
1
,
deleteAttachment
;
// no docId
if
(
!
(
typeof
docid
===
"
string
"
&&
docid
!==
""
))
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Cannot create document which id is undefined
"
,
"
reason
"
:
"
Document id is undefined
"
});
}
// no cors support
if
(
priv
.
checkCors
===
false
)
{
that
.
error
({
"
status
"
:
405
,
"
statusText
"
:
"
Method Not Allowed
"
,
"
error
"
:
"
method_not_allowed
"
,
"
message
"
:
"
Browser does not support cross domain ajax requests
"
,
"
reason
"
:
"
cors is undefined
"
});
}
secured_docid
=
priv
.
secureDocId
(
command
.
getDocId
());
url
=
priv
.
url
+
'
/
'
+
priv
.
underscoreFileExtenisons
(
secured_docid
);
// remove attachment
if
(
typeof
command
.
getAttachmentId
()
===
"
string
"
)
{
secured_attachmentid
=
priv
.
secureDocId
(
command
.
getAttachmentId
());
attachment_url
=
url
+
'
.
'
+
priv
.
underscoreFileExtenisons
(
secured_attachmentid
);
$
.
ajax
({
url
:
attachment_url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
DELETE
'
,
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
()
{
// retrieve underlying document
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
GET
'
,
async
:
true
,
dataType
:
'
text
'
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
(
response
)
{
// underlying document
doc
=
JSON
.
parse
(
response
);
// update doc._attachments
if
(
typeof
doc
.
_attachments
===
"
object
"
)
{
if
(
typeof
doc
.
_attachments
[
command
.
getAttachmentId
()]
===
"
object
"
)
{
delete
doc
.
_attachments
[
command
.
getAttachmentId
()];
if
(
priv
.
objectIsEmpty
(
doc
.
_attachments
))
{
delete
doc
.
_attachments
;
}
// PUT back to server
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
PUT
'
,
data
:
JSON
.
stringify
(
doc
),
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
// xhrFields: {withCredentials: 'true'},
success
:
function
()
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
+
'
/
'
+
command
.
getAttachmentId
()
});
},
error
:
function
()
{
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflicts
"
,
"
error
"
:
"
conflicts
"
,
"
message
"
:
"
Cannot modify document
"
,
"
reason
"
:
"
Error trying to update document attachments
"
});
}
});
}
else
{
// sure this if-else is needed?
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Error trying to update document attachments
"
});
}
}
else
{
// no attachments, we are done
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
+
'
/
'
+
command
.
getAttachmentId
()
});
}
},
error
:
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Document does not exist
"
});
}
});
},
error
:
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the attachment
"
,
"
reason
"
:
"
Error trying to remove attachment
"
});
}
});
// remove document
}
else
{
// get document to also remove all attachments
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
GET
'
,
async
:
true
,
dataType
:
'
text
'
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
(
response
)
{
var
x
;
doc
=
JSON
.
parse
(
response
);
// prepare attachment loop
if
(
typeof
doc
.
_attachments
===
"
object
"
)
{
// prepare list of attachments
for
(
x
in
doc
.
_attachments
)
{
if
(
doc
.
_attachments
.
hasOwnProperty
(
x
))
{
attachment_list
.
push
(
x
);
}
}
}
// delete document
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
DELETE
'
,
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
()
{
j
=
attachment_list
.
length
;
// no attachments, done
if
(
j
===
0
)
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
});
}
else
{
deleteAttachment
=
function
(
attachment_url
,
j
,
k
)
{
$
.
ajax
({
url
:
attachment_url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
DELETE
'
,
async
:
true
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
()
{
// all deleted, return response, need k as async couter
if
(
j
===
k
)
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
});
}
else
{
k
+=
1
;
}
},
error
:
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the attachment
"
,
"
reason
"
:
"
Error trying to remove attachment
"
});
}
});
};
for
(
i
=
0
;
i
<
j
;
i
+=
1
)
{
secured_attachmentid
=
priv
.
secureDocId
(
attachment_list
[
i
]);
attachment_url
=
url
+
'
.
'
+
priv
.
underscoreFileExtenisons
(
secured_attachmentid
);
deleteAttachment
(
attachment_url
,
j
,
k
);
}
}
},
error
:
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Error trying to remove document
"
});
}
});
},
error
:
function
()
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Document does not exist
"
});
}
});
}
};
/**
* Gets a document list from a distant dav storage
* Options:
* - {boolean} include_docs Also retrieve the actual document content.
* @method allDocs
* @param {object} command The JIO command
*/
//{
// "total_rows": 4,
// "rows": [
// {
// "id": "otherdoc",
// "key": "otherdoc",
// "value": {
// "rev": "1-3753476B70A49EA4D8C9039E7B04254C"
// }
// },{...}
// ]
//}
that
.
allDocs
=
function
(
command
)
{
var
rows
=
[],
url
,
am
=
priv
.
newAsyncModule
(),
o
=
{};
o
.
getContent
=
function
(
file
)
{
var
docid
=
priv
.
secureDocId
(
file
.
id
),
url
=
priv
.
url
+
'
/
'
+
docid
;
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
GET
'
,
async
:
true
,
dataType
:
'
text
'
,
headers
:
{
'
Authorization
'
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
)
},
success
:
function
(
content
)
{
file
.
doc
=
JSON
.
parse
(
content
);
rows
.
push
(
file
);
am
.
call
(
o
,
'
success
'
);
},
error
:
function
(
type
)
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Cannot get a document from DAVStorage
"
});
am
.
call
(
o
,
'
error
'
,
[
type
]);
}
});
};
o
.
getDocumentList
=
function
()
{
url
=
priv
.
url
+
'
/
'
;
$
.
ajax
({
url
:
url
+
'
?_=
'
+
Date
.
now
(),
type
:
'
PROPFIND
'
,
async
:
true
,
dataType
:
"
xml
"
,
crossdomain
:
true
,
headers
:
{
Authorization
:
'
Basic
'
+
btoa
(
priv
.
username
+
'
:
'
+
priv
.
password
),
Depth
:
'
1
'
},
success
:
function
(
xml
)
{
var
response
=
$
(
xml
).
find
(
'
D
\\
:response, response
'
),
len
=
response
.
length
;
if
(
len
===
1
)
{
return
am
.
call
(
o
,
'
success
'
);
}
am
.
wait
(
o
,
'
success
'
,
len
-
2
);
response
.
each
(
function
(
i
,
data
)
{
if
(
i
>
0
)
{
// exclude parent folder
var
file
=
{
value
:
{}
};
$
(
data
).
find
(
'
D
\\
:href, href
'
).
each
(
function
()
{
var
split
=
$
(
this
).
text
().
split
(
'
/
'
);
file
.
id
=
split
[
split
.
length
-
1
];
file
.
id
=
priv
.
restoreSlashes
(
file
.
id
);
file
.
key
=
file
.
id
;
});
if
(
command
.
getOption
(
'
include_docs
'
))
{
am
.
call
(
o
,
'
getContent
'
,
[
file
]);
}
else
{
rows
.
push
(
file
);
am
.
call
(
o
,
'
success
'
);
}
}
});
},
error
:
function
(
type
)
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Cannot get a document list from DAVStorage
"
});
am
.
call
(
o
,
'
retry
'
,
[
type
]);
}
});
};
o
.
retry
=
function
(
error
)
{
am
.
neverCall
(
o
,
'
retry
'
);
am
.
neverCall
(
o
,
'
success
'
);
am
.
neverCall
(
o
,
'
error
'
);
that
.
retry
(
error
);
};
o
.
error
=
function
(
error
)
{
am
.
neverCall
(
o
,
'
retry
'
);
am
.
neverCall
(
o
,
'
success
'
);
am
.
neverCall
(
o
,
'
error
'
);
that
.
error
(
error
);
};
o
.
success
=
function
()
{
am
.
neverCall
(
o
,
'
retry
'
);
am
.
neverCall
(
o
,
'
success
'
);
am
.
neverCall
(
o
,
'
error
'
);
that
.
success
({
total_rows
:
rows
.
length
,
rows
:
rows
});
};
// first get the XML list
am
.
call
(
o
,
'
getDocumentList
'
);
};
return
that
;
});
\ No newline at end of file
lib/jio/jio.js
0 → 100644
View file @
720d75aa
(
function
(
scope
,
hex_md5
)
{
"
use strict
"
;
var
localstorage
;
if
(
typeof
localStorage
!==
"
undefined
"
)
{
localstorage
=
{
getItem
:
function
(
item
)
{
var
value
=
localStorage
.
getItem
(
item
);
return
value
===
null
?
null
:
JSON
.
parse
(
value
);
},
setItem
:
function
(
item
,
value
)
{
return
localStorage
.
setItem
(
item
,
JSON
.
stringify
(
value
));
},
removeItem
:
function
(
item
)
{
delete
localStorage
[
item
];
},
clone
:
function
()
{
return
JSON
.
parse
(
JSON
.
stringify
(
localStorage
));
}
};
}
else
{
(
function
()
{
var
pseudo_localStorage
=
{};
localstorage
=
{
getItem
:
function
(
item
)
{
var
value
=
pseudo_localStorage
[
item
];
return
value
===
undefined
?
null
:
JSON
.
parse
(
pseudo_localStorage
[
item
]);
},
setItem
:
function
(
item
,
value
)
{
pseudo_localStorage
[
item
]
=
JSON
.
stringify
(
value
);
},
removeItem
:
function
(
item
)
{
delete
pseudo_localStorage
[
item
];
},
clone
:
function
()
{
return
JSON
.
parse
(
JSON
.
stringify
(
pseudo_localStorage
));
}
};
}());
}
/*jslint indent:2, maxlen: 80, sloppy: true */
var
jioException
=
function
(
spec
,
my
)
{
var
that
=
{};
spec
=
spec
||
{};
my
=
my
||
{};
that
.
name
=
'
jioException
'
;
that
.
message
=
spec
.
message
||
'
Unknown Reason.
'
;
that
.
toString
=
function
()
{
return
that
.
name
+
'
:
'
+
that
.
message
;
};
return
that
;
};
var
invalidCommandState
=
function
(
spec
,
my
)
{
var
that
=
jioException
(
spec
,
my
),
command
=
spec
.
command
;
spec
=
spec
||
{};
that
.
name
=
'
invalidCommandState
'
;
that
.
toString
=
function
()
{
return
that
.
name
+
'
:
'
+
command
.
getLabel
()
+
'
,
'
+
that
.
message
;
};
return
that
;
};
var
invalidStorage
=
function
(
spec
,
my
)
{
var
that
=
jioException
(
spec
,
my
),
type
=
spec
.
storage
.
getType
();
spec
=
spec
||
{};
that
.
name
=
'
invalidStorage
'
;
that
.
toString
=
function
()
{
return
that
.
name
+
'
:
'
+
'
Type "
'
+
type
+
'
",
'
+
that
.
message
;
};
return
that
;
};
var
invalidStorageType
=
function
(
spec
,
my
)
{
var
that
=
jioException
(
spec
,
my
),
type
=
spec
.
type
;
that
.
name
=
'
invalidStorageType
'
;
that
.
toString
=
function
()
{
return
that
.
name
+
'
:
'
+
type
+
'
,
'
+
that
.
message
;
};
return
that
;
};
var
jobNotReadyException
=
function
(
spec
,
my
)
{
var
that
=
jioException
(
spec
,
my
);
that
.
name
=
'
jobNotReadyException
'
;
return
that
;
};
var
tooMuchTriesJobException
=
function
(
spec
,
my
)
{
var
that
=
jioException
(
spec
,
my
);
that
.
name
=
'
tooMuchTriesJobException
'
;
return
that
;
};
var
invalidJobException
=
function
(
spec
,
my
)
{
var
that
=
jioException
(
spec
,
my
);
that
.
name
=
'
invalidJobException
'
;
return
that
;
};
var
jio
=
function
(
spec
)
{
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global command: true, jobManager: true, job: true */
var
storage
=
function
(
spec
,
my
)
{
var
that
=
{},
priv
=
{};
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
priv
.
type
=
spec
.
type
||
''
;
// Methods //
Object
.
defineProperty
(
that
,
"
getType
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
priv
.
type
;
}
});
/**
* Execute the command on this storage.
* @method execute
* @param {object} command The command
*/
that
.
execute
=
function
(
command
)
{
that
.
success
=
command
.
success
;
that
.
error
=
command
.
error
;
that
.
retry
=
command
.
retry
;
that
.
end
=
command
.
end
;
if
(
that
.
validate
(
command
))
{
command
.
executeOn
(
that
);
}
};
/**
* Override this function to validate specifications.
* @method isValid
* @return {boolean} true if ok, else false.
*/
that
.
isValid
=
function
()
{
return
true
;
};
that
.
validate
=
function
()
{
var
mess
=
that
.
validateState
();
if
(
mess
)
{
that
.
error
({
"
status
"
:
0
,
"
statusText
"
:
"
Invalid Storage
"
,
"
error
"
:
"
invalid_storage
"
,
"
message
"
:
mess
,
"
reason
"
:
mess
});
return
false
;
}
return
true
;
};
/**
* Returns a serialized version of this storage.
* @method serialized
* @return {object} The serialized storage.
*/
that
.
serialized
=
function
()
{
var
o
=
that
.
specToStore
()
||
{};
o
.
type
=
that
.
getType
();
return
o
;
};
/**
* Returns an object containing spec to store on localStorage, in order to
* be restored later if something wrong happen.
* Override this method!
* @method specToStore
* @return {object} The spec to store
*/
that
.
specToStore
=
function
()
{
return
{};
};
/**
* Validate the storage state. It returns a empty string all is ok.
* @method validateState
* @return {string} empty: ok, else error message.
*/
that
.
validateState
=
function
()
{
return
''
;
};
that
.
post
=
function
()
{
setTimeout
(
function
()
{
that
.
error
({
"
status
"
:
0
,
"
statusText
"
:
"
Not Implemented
"
,
"
error
"
:
"
not_implemented
"
,
"
message
"
:
"
\"
Post
\"
command is not implemented
"
,
"
reason
"
:
"
Command not implemented
"
});
});
};
that
.
put
=
function
()
{
setTimeout
(
function
()
{
that
.
error
({
"
status
"
:
0
,
"
statusText
"
:
"
Not Implemented
"
,
"
error
"
:
"
not_implemented
"
,
"
message
"
:
"
\"
Put
\"
command is not implemented
"
,
"
reason
"
:
"
Command not implemented
"
});
});
};
that
.
putAttachment
=
function
()
{
setTimeout
(
function
()
{
that
.
error
({
"
status
"
:
0
,
"
statusText
"
:
"
Not Implemented
"
,
"
error
"
:
"
not_implemented
"
,
"
message
"
:
"
\"
PutAttachment
\"
command is not implemented
"
,
"
reason
"
:
"
Command not implemented
"
});
});
};
that
.
get
=
function
()
{
setTimeout
(
function
()
{
that
.
error
({
"
status
"
:
0
,
"
statusText
"
:
"
Not Implemented
"
,
"
error
"
:
"
not_implemented
"
,
"
message
"
:
"
\"
Get
\"
command is not implemented
"
,
"
reason
"
:
"
Command not implemented
"
});
});
};
that
.
allDocs
=
function
()
{
setTimeout
(
function
()
{
that
.
error
({
"
status
"
:
0
,
"
statusText
"
:
"
Not Implemented
"
,
"
error
"
:
"
not_implemented
"
,
"
message
"
:
"
\"
AllDocs
\"
command is not implemented
"
,
"
reason
"
:
"
Command not implemented
"
});
});
};
that
.
remove
=
function
()
{
setTimeout
(
function
()
{
that
.
error
({
"
status
"
:
0
,
"
statusText
"
:
"
Not Implemented
"
,
"
error
"
:
"
not_implemented
"
,
"
message
"
:
"
\"
Remove
\"
command is not implemented
"
,
"
reason
"
:
"
Command not implemented
"
});
});
};
that
.
success
=
function
()
{};
that
.
retry
=
function
()
{};
that
.
error
=
function
()
{};
that
.
end
=
function
()
{};
// terminate the current job.
priv
.
newCommand
=
function
(
method
,
spec
)
{
var
o
=
spec
||
{};
o
.
label
=
method
;
return
command
(
o
,
my
);
};
priv
.
storage
=
my
.
storage
;
delete
my
.
storage
;
that
.
addJob
=
function
(
method
,
storage_spec
,
doc
,
option
,
success
,
error
)
{
var
command_opt
=
{
options
:
option
,
callbacks
:
{
success
:
success
,
error
:
error
}
};
if
(
doc
)
{
if
(
method
===
'
get
'
)
{
command_opt
.
docid
=
doc
;
}
else
{
command_opt
.
doc
=
doc
;
}
}
jobManager
.
addJob
(
job
({
storage
:
priv
.
storage
(
storage_spec
||
{}),
command
:
priv
.
newCommand
(
method
,
command_opt
)
},
my
));
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global command: true */
var
allDocsCommand
=
function
(
spec
,
my
)
{
var
that
=
command
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
allDocs
'
;
};
that
.
executeOn
=
function
(
storage
)
{
storage
.
allDocs
(
that
);
};
that
.
canBeRestored
=
function
()
{
return
false
;
};
that
.
validateState
=
function
()
{
return
true
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global postCommand: true, putCommand: true, getCommand: true,
removeCommand: true, allDocsCommand: true,
putAttachmentCommand: true, failStatus: true, doneStatus: true,
hex_md5: true */
var
command
=
function
(
spec
,
my
)
{
var
that
=
{},
priv
=
{};
spec
=
spec
||
{};
my
=
my
||
{};
priv
.
commandlist
=
{
'
post
'
:
postCommand
,
'
put
'
:
putCommand
,
'
get
'
:
getCommand
,
'
remove
'
:
removeCommand
,
'
allDocs
'
:
allDocsCommand
,
'
putAttachment
'
:
putAttachmentCommand
};
// creates the good command thanks to his label
if
(
spec
.
label
&&
priv
.
commandlist
[
spec
.
label
])
{
priv
.
label
=
spec
.
label
;
delete
spec
.
label
;
return
priv
.
commandlist
[
priv
.
label
](
spec
,
my
);
}
priv
.
tried
=
0
;
priv
.
doc
=
spec
.
doc
||
{};
if
(
typeof
priv
.
doc
!==
"
object
"
)
{
priv
.
doc
=
{
"
_id
"
:
priv
.
doc
.
toString
()
};
}
priv
.
docid
=
spec
.
docid
||
priv
.
doc
.
_id
;
priv
.
option
=
spec
.
options
||
{};
priv
.
callbacks
=
spec
.
callbacks
||
{};
priv
.
success
=
priv
.
callbacks
.
success
||
function
()
{};
priv
.
error
=
priv
.
callbacks
.
error
||
function
()
{};
priv
.
retry
=
function
()
{
that
.
error
({
status
:
13
,
statusText
:
'
Fail Retry
'
,
error
:
'
fail_retry
'
,
message
:
'
Impossible to retry.
'
,
reason
:
'
Impossible to retry.
'
});
};
priv
.
end
=
function
()
{};
priv
.
on_going
=
false
;
// Methods //
/**
* Returns a serialized version of this command.
* @method serialized
* @return {object} The serialized command.
*/
that
.
serialized
=
function
()
{
var
o
=
{};
o
.
label
=
that
.
getLabel
();
o
.
tried
=
priv
.
tried
;
o
.
doc
=
that
.
cloneDoc
();
o
.
option
=
that
.
cloneOption
();
return
o
;
};
/**
* Returns the label of the command.
* @method getLabel
* @return {string} The label.
*/
that
.
getLabel
=
function
()
{
return
'
command
'
;
};
/**
* Gets the document id
* @method getDocId
* @return {string} The document id
*/
that
.
getDocId
=
function
()
{
if
(
typeof
priv
.
docid
!==
"
string
"
)
{
return
undefined
;
}
return
priv
.
docid
.
split
(
'
/
'
)[
0
];
};
/**
* Gets the attachment id
* @method getAttachmentId
* @return {string} The attachment id
*/
that
.
getAttachmentId
=
function
()
{
if
(
typeof
priv
.
docid
!==
"
string
"
)
{
return
undefined
;
}
return
priv
.
docid
.
split
(
'
/
'
)[
1
];
};
/**
* Returns the label of the command.
* @method getDoc
* @return {object} The document.
*/
that
.
getDoc
=
function
()
{
return
priv
.
doc
;
};
/**
* Returns the data of the attachment
* @method getAttachmentData
* @return {string} The data
*/
that
.
getAttachmentData
=
function
()
{
return
priv
.
doc
.
_data
||
""
;
};
/**
* Returns the data length of the attachment
* @method getAttachmentLength
* @return {number} The length
*/
that
.
getAttachmentLength
=
function
()
{
return
(
priv
.
doc
.
_data
||
""
).
length
;
};
/**
* Returns the mimetype of the attachment
* @method getAttachmentMimeType
* @return {string} The mimetype
*/
that
.
getAttachmentMimeType
=
function
()
{
return
priv
.
doc
.
_mimetype
;
};
/**
* Generate the md5sum of the attachment data
* @method md5SumAttachmentData
* @return {string} The md5sum
*/
that
.
md5SumAttachmentData
=
function
()
{
return
hex_md5
(
priv
.
doc
.
_data
||
""
);
};
/**
* Returns an information about the document.
* @method getDocInfo
* @param {string} infoname The info name.
* @return The info value.
*/
that
.
getDocInfo
=
function
(
infoname
)
{
return
priv
.
doc
[
infoname
];
};
/**
* Returns the value of an option.
* @method getOption
* @param {string} optionname The option name.
* @return The option value.
*/
that
.
getOption
=
function
(
optionname
)
{
return
priv
.
option
[
optionname
];
};
/**
* Validates the storage.
* @param {object} storage The storage.
*/
that
.
validate
=
function
(
storage
)
{
if
(
typeof
priv
.
docid
===
"
string
"
&&
!
priv
.
docid
.
match
(
"
^[^
\
/]+([
\
/][^
\
/]+)?$
"
))
{
that
.
error
({
status
:
21
,
statusText
:
'
Invalid Document Id
'
,
error
:
'
invalid_document_id
'
,
message
:
'
The document id must be like "abc" or "abc/def".
'
,
reason
:
'
The document id is no like "abc" or "abc/def"
'
});
return
false
;
}
if
(
!
that
.
validateState
())
{
return
false
;
}
return
storage
.
validate
();
};
/*
* Extend this function
*/
that
.
validateState
=
function
()
{
return
true
;
};
/**
* Check if the command can be retried.
* @method canBeRetried
* @return {boolean} The result
*/
that
.
canBeRetried
=
function
()
{
return
(
priv
.
option
.
max_retry
===
undefined
||
priv
.
option
.
max_retry
===
0
||
priv
.
tried
<
priv
.
option
.
max_retry
);
};
/**
* Gets the number time the command has been tried.
* @method getTried
* @return {number} The number of time the command has been tried
*/
that
.
getTried
=
function
()
{
return
priv
.
tried
;
};
/**
* Delegate actual excecution the storage.
* @param {object} storage The storage.
*/
that
.
execute
=
function
(
storage
)
{
if
(
!
priv
.
on_going
)
{
if
(
that
.
validate
(
storage
))
{
priv
.
tried
+=
1
;
priv
.
on_going
=
true
;
storage
.
execute
(
that
);
}
}
};
/**
* Execute the good method from the storage.
* Override this function.
* @method executeOn
* @param {object} storage The storage.
*/
that
.
executeOn
=
function
(
storage
)
{};
that
.
success
=
function
(
return_value
)
{
priv
.
on_going
=
false
;
priv
.
success
(
return_value
);
priv
.
end
(
doneStatus
());
};
that
.
retry
=
function
(
return_error
)
{
priv
.
on_going
=
false
;
if
(
that
.
canBeRetried
())
{
priv
.
retry
();
}
else
{
that
.
error
(
return_error
);
}
};
that
.
error
=
function
(
return_error
)
{
priv
.
on_going
=
false
;
priv
.
error
(
return_error
);
priv
.
end
(
failStatus
());
};
that
.
end
=
function
()
{
priv
.
end
(
doneStatus
());
};
that
.
onSuccessDo
=
function
(
fun
)
{
if
(
fun
)
{
priv
.
success
=
fun
;
}
else
{
return
priv
.
success
;
}
};
that
.
onErrorDo
=
function
(
fun
)
{
if
(
fun
)
{
priv
.
error
=
fun
;
}
else
{
return
priv
.
error
;
}
};
that
.
onEndDo
=
function
(
fun
)
{
priv
.
end
=
fun
;
};
that
.
onRetryDo
=
function
(
fun
)
{
priv
.
retry
=
fun
;
};
/**
* Is the command can be restored by another JIO : yes.
* @method canBeRestored
* @return {boolean} true
*/
that
.
canBeRestored
=
function
()
{
return
true
;
};
/**
* Clones the command and returns it.
* @method clone
* @return {object} The cloned command.
*/
that
.
clone
=
function
()
{
return
command
(
that
.
serialized
(),
my
);
};
/**
* Clones the command options and returns the clone version.
* @method cloneOption
* @return {object} The clone of the command options.
*/
that
.
cloneOption
=
function
()
{
return
JSON
.
parse
(
JSON
.
stringify
(
priv
.
option
));
};
/**
* Clones the document and returns the clone version.
* @method cloneDoc
* @return {object} The clone of the document.
*/
that
.
cloneDoc
=
function
()
{
return
JSON
.
parse
(
JSON
.
stringify
(
priv
.
doc
));
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global command: true */
var
getCommand
=
function
(
spec
,
my
)
{
var
that
=
command
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
get
'
;
};
that
.
validateState
=
function
()
{
if
(
!
(
typeof
that
.
getDocId
()
===
"
string
"
&&
that
.
getDocId
()
!==
""
))
{
that
.
error
({
"
status
"
:
20
,
"
statusText
"
:
"
Document Id Required
"
,
"
error
"
:
"
document_id_required
"
,
"
message
"
:
"
The document id is not provided
"
,
"
reason
"
:
"
Document id is undefined
"
});
return
false
;
}
if
(
typeof
that
.
getAttachmentId
()
===
"
string
"
)
{
if
(
that
.
getAttachmentId
()
===
""
)
{
that
.
error
({
"
status
"
:
23
,
"
statusText
"
:
"
Invalid Attachment Id
"
,
"
error
"
:
"
invalid_attachment_id
"
,
"
message
"
:
"
The attachment id must not be an empty string
"
,
"
reason
"
:
"
Attachment id is empty
"
});
return
false
;
}
}
return
true
;
};
that
.
executeOn
=
function
(
storage
)
{
storage
.
get
(
that
);
};
that
.
canBeRestored
=
function
()
{
return
false
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global command: true */
var
postCommand
=
function
(
spec
,
my
)
{
var
that
=
command
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Methods //
that
.
getLabel
=
function
()
{
return
'
post
'
;
};
that
.
validateState
=
function
()
{
if
(
that
.
getAttachmentId
()
!==
undefined
)
{
that
.
error
({
"
status
"
:
21
,
"
statusText
"
:
"
Invalid Document Id
"
,
"
error
"
:
"
invalid_document_id
"
,
"
message
"
:
"
The document id contains '/' characters
"
+
"
which are forbidden
"
,
"
reason
"
:
"
Document id contains '/' character(s)
"
});
return
false
;
}
return
true
;
};
that
.
executeOn
=
function
(
storage
)
{
storage
.
post
(
that
);
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global command: true */
var
putAttachmentCommand
=
function
(
spec
,
my
)
{
var
that
=
command
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
putAttachment
'
;
};
that
.
executeOn
=
function
(
storage
)
{
storage
.
putAttachment
(
that
);
};
that
.
validateState
=
function
()
{
if
(
!
(
typeof
that
.
getDocId
()
===
"
string
"
&&
that
.
getDocId
()
!==
""
))
{
that
.
error
({
"
status
"
:
20
,
"
statusText
"
:
"
Document Id Required
"
,
"
error
"
:
"
document_id_required
"
,
"
message
"
:
"
The document id is not provided
"
,
"
reason
"
:
"
Document id is undefined
"
});
return
false
;
}
if
(
typeof
that
.
getAttachmentId
()
!==
"
string
"
)
{
that
.
error
({
"
status
"
:
22
,
"
statusText
"
:
"
Attachment Id Required
"
,
"
error
"
:
"
attachment_id_required
"
,
"
message
"
:
"
The attachment id must be set
"
,
"
reason
"
:
"
Attachment id not set
"
});
return
false
;
}
if
(
that
.
getAttachmentId
()
===
""
)
{
that
.
error
({
"
status
"
:
23
,
"
statusText
"
:
"
Invalid Attachment Id
"
,
"
error
"
:
"
invalid_attachment_id
"
,
"
message
"
:
"
The attachment id must not be an empty string
"
,
"
reason
"
:
"
Attachment id is empty
"
});
}
return
true
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global command: true */
var
putCommand
=
function
(
spec
,
my
)
{
var
that
=
command
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Methods //
that
.
getLabel
=
function
()
{
return
'
put
'
;
};
that
.
validateState
=
function
()
{
if
(
!
(
typeof
that
.
getDocId
()
===
"
string
"
&&
that
.
getDocId
()
!==
""
))
{
that
.
error
({
"
status
"
:
20
,
"
statusText
"
:
"
Document Id Required
"
,
"
error
"
:
"
document_id_required
"
,
"
message
"
:
"
The document id is not provided
"
,
"
reason
"
:
"
Document id is undefined
"
});
return
false
;
}
if
(
that
.
getAttachmentId
()
!==
undefined
)
{
that
.
error
({
"
status
"
:
21
,
"
statusText
"
:
"
Invalid Document Id
"
,
"
error
"
:
"
invalid_document_id
"
,
"
message
"
:
"
The document id contains '/' characters
"
+
"
which are forbidden
"
,
"
reason
"
:
"
Document id contains '/' character(s)
"
});
return
false
;
}
return
true
;
};
that
.
executeOn
=
function
(
storage
)
{
storage
.
put
(
that
);
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global command: true */
var
removeCommand
=
function
(
spec
,
my
)
{
var
that
=
command
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
remove
'
;
};
that
.
validateState
=
function
()
{
if
(
!
(
typeof
that
.
getDocId
()
===
"
string
"
&&
that
.
getDocId
()
!==
""
))
{
that
.
error
({
"
status
"
:
20
,
"
statusText
"
:
"
Document Id Required
"
,
"
error
"
:
"
document_id_required
"
,
"
message
"
:
"
The document id is not provided
"
,
"
reason
"
:
"
Document id is undefined
"
});
return
false
;
}
if
(
typeof
that
.
getAttachmentId
()
===
"
string
"
)
{
if
(
that
.
getAttachmentId
()
===
""
)
{
that
.
error
({
"
status
"
:
23
,
"
statusText
"
:
"
Invalid Attachment Id
"
,
"
error
"
:
"
invalid_attachment_id
"
,
"
message
"
:
"
The attachment id must not be an empty string
"
,
"
reason
"
:
"
Attachment id is empty
"
});
return
false
;
}
}
return
true
;
};
that
.
executeOn
=
function
(
storage
)
{
storage
.
remove
(
that
);
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jobStatus: true */
var
doneStatus
=
function
(
spec
,
my
)
{
var
that
=
jobStatus
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
done
'
;
};
that
.
canStart
=
function
()
{
return
false
;
};
that
.
canRestart
=
function
()
{
return
false
;
};
that
.
isDone
=
function
()
{
return
true
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jobStatus: true */
var
failStatus
=
function
(
spec
,
my
)
{
var
that
=
jobStatus
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
fail
'
;
};
that
.
canStart
=
function
()
{
return
false
;
};
that
.
canRestart
=
function
()
{
return
true
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jobStatus: true */
var
initialStatus
=
function
(
spec
,
my
)
{
var
that
=
jobStatus
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
"
initial
"
;
};
that
.
canStart
=
function
()
{
return
true
;
};
that
.
canRestart
=
function
()
{
return
true
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jobStatus: true */
var
jobStatus
=
function
(
spec
,
my
)
{
var
that
=
{};
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
job status
'
;
};
that
.
canStart
=
function
()
{};
that
.
canRestart
=
function
()
{};
that
.
serialized
=
function
()
{
return
{
"
label
"
:
that
.
getLabel
()};
};
that
.
isWaitStatus
=
function
()
{
return
false
;
};
that
.
isDone
=
function
()
{
return
false
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jobStatus: true */
var
onGoingStatus
=
function
(
spec
,
my
)
{
var
that
=
jobStatus
(
spec
,
my
);
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
// Methods //
that
.
getLabel
=
function
()
{
return
'
on going
'
;
};
that
.
canStart
=
function
()
{
return
false
;
};
that
.
canRestart
=
function
()
{
return
false
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jobStatus: true, jobManager: true */
var
waitStatus
=
function
(
spec
,
my
)
{
var
that
=
jobStatus
(
spec
,
my
),
priv
=
{};
spec
=
spec
||
{};
my
=
my
||
{};
// Attributes //
priv
.
job_id_array
=
spec
.
job_id_array
||
[];
priv
.
threshold
=
0
;
// Methods //
/**
* Returns the label of this status.
* @method getLabel
* @return {string} The label: 'wait'.
*/
that
.
getLabel
=
function
()
{
return
'
wait
'
;
};
/**
* Refresh the job id array to wait.
* @method refreshJobIdArray
*/
priv
.
refreshJobIdArray
=
function
()
{
var
tmp_job_id_array
=
[],
i
;
for
(
i
=
0
;
i
<
priv
.
job_id_array
.
length
;
i
+=
1
)
{
if
(
jobManager
.
jobIdExists
(
priv
.
job_id_array
[
i
]))
{
tmp_job_id_array
.
push
(
priv
.
job_id_array
[
i
]);
}
}
priv
.
job_id_array
=
tmp_job_id_array
;
};
/**
* The status must wait for the job end before start again.
* @method waitForJob
* @param {object} job The job to wait for.
*/
that
.
waitForJob
=
function
(
job
)
{
var
i
;
for
(
i
=
0
;
i
<
priv
.
job_id_array
.
length
;
i
+=
1
)
{
if
(
priv
.
job_id_array
[
i
]
===
job
.
getId
())
{
return
;
}
}
priv
.
job_id_array
.
push
(
job
.
getId
());
};
/**
* The status stops to wait for this job.
* @method dontWaitForJob
* @param {object} job The job to stop waiting for.
*/
that
.
dontWaitForJob
=
function
(
job
)
{
var
i
,
tmp_job_id_array
=
[];
for
(
i
=
0
;
i
<
priv
.
job_id_array
.
length
;
i
+=
1
)
{
if
(
priv
.
job_id_array
[
i
]
!==
job
.
getId
())
{
tmp_job_id_array
.
push
(
priv
.
job_id_array
[
i
]);
}
}
priv
.
job_id_array
=
tmp_job_id_array
;
};
/**
* The status must wait for some milliseconds.
* @method waitForTime
* @param {number} ms The number of milliseconds
*/
that
.
waitForTime
=
function
(
ms
)
{
priv
.
threshold
=
Date
.
now
()
+
ms
;
};
/**
* The status stops to wait for some time.
* @method stopWaitForTime
*/
that
.
stopWaitForTime
=
function
()
{
priv
.
threshold
=
0
;
};
that
.
canStart
=
function
()
{
priv
.
refreshJobIdArray
();
return
(
priv
.
job_id_array
.
length
===
0
&&
Date
.
now
()
>=
priv
.
threshold
);
};
that
.
canRestart
=
function
()
{
return
that
.
canStart
();
};
that
.
serialized
=
function
()
{
return
{
"
label
"
:
that
.
getLabel
(),
"
waitfortime
"
:
priv
.
threshold
,
"
waitforjob
"
:
priv
.
job_id_array
};
};
/**
* Checks if this status is waitStatus
* @method isWaitStatus
* @return {boolean} true
*/
that
.
isWaitStatus
=
function
()
{
return
true
;
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jobIdHandler: true, initialStatus: true, invalidJobException: true,
waitStatus: true, failStatus: true, tooMuchTriesJobException: true,
jobManager: true, jobNotReadyException: true, onGoingStatus: true */
var
job
=
function
(
spec
)
{
var
that
=
{},
priv
=
{};
spec
=
spec
||
{};
priv
.
id
=
jobIdHandler
.
nextId
();
priv
.
command
=
spec
.
command
;
priv
.
storage
=
spec
.
storage
;
priv
.
status
=
initialStatus
();
priv
.
date
=
new
Date
();
// Initialize //
if
(
!
priv
.
storage
)
{
throw
invalidJobException
({
job
:
that
,
message
:
'
No storage set
'
});
}
if
(
!
priv
.
command
)
{
throw
invalidJobException
({
job
:
that
,
message
:
'
No command set
'
});
}
// Methods //
/**
* Returns the job command.
* @method getCommand
* @return {object} The job command.
*/
that
.
getCommand
=
function
()
{
return
priv
.
command
;
};
that
.
getStatus
=
function
()
{
return
priv
.
status
;
};
that
.
getId
=
function
()
{
return
priv
.
id
;
};
that
.
getStorage
=
function
()
{
return
priv
.
storage
;
};
that
.
getDate
=
function
()
{
return
priv
.
date
;
};
/**
* Checks if the job is ready.
* @method isReady
* @return {boolean} true if ready, else false.
*/
that
.
isReady
=
function
()
{
if
(
priv
.
command
.
getTried
()
===
0
)
{
return
priv
.
status
.
canStart
();
}
return
priv
.
status
.
canRestart
();
};
/**
* Returns a serialized version of this job.
* @method serialized
* @return {object} The serialized job.
*/
that
.
serialized
=
function
()
{
return
{
id
:
priv
.
id
,
date
:
priv
.
date
.
getTime
(),
status
:
priv
.
status
.
serialized
(),
command
:
priv
.
command
.
serialized
(),
storage
:
priv
.
storage
.
serialized
()
};
};
/**
* Tells the job to wait for another one.
* @method waitForJob
* @param {object} job The job to wait for.
*/
that
.
waitForJob
=
function
(
job
)
{
if
(
priv
.
status
.
getLabel
()
!==
'
wait
'
)
{
priv
.
status
=
waitStatus
({});
}
priv
.
status
.
waitForJob
(
job
);
};
/**
* Tells the job to do not wait for a job.
* @method dontWaitForJob
* @param {object} job The other job.
*/
that
.
dontWaitFor
=
function
(
job
)
{
if
(
priv
.
status
.
getLabel
()
===
'
wait
'
)
{
priv
.
status
.
dontWaitForJob
(
job
);
}
};
/**
* Tells the job to wait for a while.
* @method waitForTime
* @param {number} ms Time to wait in millisecond.
*/
that
.
waitForTime
=
function
(
ms
)
{
if
(
priv
.
status
.
getLabel
()
!==
'
wait
'
)
{
priv
.
status
=
waitStatus
({});
}
priv
.
status
.
waitForTime
(
ms
);
};
/**
* Tells the job to do not wait for a while anymore.
* @method stopWaitForTime
*/
that
.
stopWaitForTime
=
function
()
{
if
(
priv
.
status
.
getLabel
()
===
'
wait
'
)
{
priv
.
status
.
stopWaitForTime
();
}
};
that
.
eliminated
=
function
()
{
priv
.
command
.
error
({
status
:
10
,
statusText
:
'
Stopped
'
,
error
:
'
stopped
'
,
message
:
'
This job has been stopped by another one.
'
,
reason
:
'
this job has been stopped by another one
'
});
};
that
.
notAccepted
=
function
()
{
priv
.
command
.
onEndDo
(
function
()
{
priv
.
status
=
failStatus
();
jobManager
.
terminateJob
(
that
);
});
priv
.
command
.
error
({
status
:
11
,
statusText
:
'
Not Accepted
'
,
error
:
'
not_accepted
'
,
message
:
'
This job is already running.
'
,
reason
:
'
this job is already running
'
});
};
/**
* Updates the date of the job with the another one.
* @method update
* @param {object} job The other job.
*/
that
.
update
=
function
(
job
)
{
priv
.
command
.
error
({
status
:
12
,
statusText
:
'
Replaced
'
,
error
:
'
replaced
'
,
message
:
'
Job has been replaced by another one.
'
,
reason
:
'
job has been replaced by another one
'
});
priv
.
date
=
new
Date
(
job
.
getDate
().
getTime
());
priv
.
command
=
job
.
getCommand
();
priv
.
status
=
job
.
getStatus
();
};
/**
* Executes this job.
* @method execute
*/
that
.
execute
=
function
()
{
if
(
!
that
.
getCommand
().
canBeRetried
())
{
throw
tooMuchTriesJobException
({
job
:
that
,
message
:
'
The job was invoked too much time.
'
});
}
if
(
!
that
.
isReady
())
{
throw
jobNotReadyException
({
job
:
that
,
message
:
'
Can not execute this job.
'
});
}
priv
.
status
=
onGoingStatus
();
priv
.
command
.
onRetryDo
(
function
()
{
var
ms
=
priv
.
command
.
getTried
();
ms
=
ms
*
ms
*
200
;
if
(
ms
>
10000
)
{
ms
=
10000
;
}
that
.
waitForTime
(
ms
);
});
priv
.
command
.
onEndDo
(
function
(
status
)
{
priv
.
status
=
status
;
jobManager
.
terminateJob
(
that
);
});
priv
.
command
.
execute
(
priv
.
storage
);
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global announcement: true */
var
announcement
=
function
(
spec
,
my
)
{
var
that
=
{},
callback_a
=
[],
announcer
=
spec
.
announcer
||
{};
spec
=
spec
||
{};
my
=
my
||
{};
// Methods //
that
.
add
=
function
(
callback
)
{
callback_a
.
push
(
callback
);
};
that
.
remove
=
function
(
callback
)
{
var
i
,
tmp_callback_a
=
[];
for
(
i
=
0
;
i
<
callback_a
.
length
;
i
+=
1
)
{
if
(
callback_a
[
i
]
!==
callback
)
{
tmp_callback_a
.
push
(
callback_a
[
i
]);
}
}
callback_a
=
tmp_callback_a
;
};
that
.
register
=
function
()
{
announcer
.
register
(
that
);
};
that
.
unregister
=
function
()
{
announcer
.
unregister
(
that
);
};
that
.
trigger
=
function
(
args
)
{
var
i
;
for
(
i
=
0
;
i
<
callback_a
.
length
;
i
+=
1
)
{
callback_a
[
i
].
apply
(
null
,
args
);
}
};
return
that
;
};
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global localstorage: true, setInterval: true, clearInterval: true */
var
activityUpdater
=
(
function
(
spec
,
my
)
{
var
that
=
{},
priv
=
{};
spec
=
spec
||
{};
my
=
my
||
{};
priv
.
id
=
spec
.
id
||
0
;
priv
.
interval
=
400
;
priv
.
interval_id
=
null
;
// Methods //
/**
* Update the last activity date in the localStorage.
* @method touch
*/
priv
.
touch
=
function
()
{
localstorage
.
setItem
(
'
jio/id/
'
+
priv
.
id
,
Date
.
now
());
};
/**
* Sets the jio id into the activity.
* @method setId
* @param {number} id The jio id.
*/
that
.
setId
=
function
(
id
)
{
priv
.
id
=
id
;
};
/**
* Sets the interval delay between two updates.
* @method setIntervalDelay
* @param {number} ms In milliseconds
*/
that
.
setIntervalDelay
=
function
(
ms
)
{
priv
.
interval
=
ms
;
};
/**
* Gets the interval delay.
* @method getIntervalDelay
* @return {number} The interval delay.
*/
that
.
getIntervalDelay
=
function
()
{
return
priv
.
interval
;
};
/**
* Starts the activity updater. It will update regulary the last activity
* date in the localStorage to show to other jio instance that this instance
* is active.
* @method start
*/
that
.
start
=
function
()
{
if
(
!
priv
.
interval_id
)
{
priv
.
touch
();
priv
.
interval_id
=
setInterval
(
function
()
{
priv
.
touch
();
},
priv
.
interval
);
}
};
/**
* Stops the activity updater.
* @method stop
*/
that
.
stop
=
function
()
{
if
(
priv
.
interval_id
!==
null
)
{
clearInterval
(
priv
.
interval_id
);
priv
.
interval_id
=
null
;
}
};
return
that
;
}());
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global announcement: true */
var
announcer
=
(
function
(
spec
,
my
)
{
var
that
=
{},
announcement_o
=
{};
spec
=
spec
||
{};
my
=
my
||
{};
// Methods //
that
.
register
=
function
(
name
)
{
if
(
!
announcement_o
[
name
])
{
announcement_o
[
name
]
=
announcement
();
}
};
that
.
unregister
=
function
(
name
)
{
if
(
announcement_o
[
name
])
{
delete
announcement_o
[
name
];
}
};
that
.
at
=
function
(
name
)
{
return
announcement_o
[
name
];
};
that
.
on
=
function
(
name
,
callback
)
{
that
.
register
(
name
);
that
.
at
(
name
).
add
(
callback
);
};
that
.
trigger
=
function
(
name
,
args
)
{
that
.
at
(
name
).
trigger
(
args
);
};
return
that
;
}());
/*jslint indent: 2, maxlen: 80, sloppy: true */
var
jobIdHandler
=
(
function
(
spec
)
{
var
that
=
{},
id
=
0
;
spec
=
spec
||
{};
// Methods //
that
.
nextId
=
function
()
{
id
=
id
+
1
;
return
id
;
};
return
that
;
}());
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global localstorage: true, setInterval: true, clearInterval: true,
command: true, job: true, jobRules: true */
var
jobManager
=
(
function
(
spec
)
{
var
that
=
{},
job_array_name
=
'
jio/job_array
'
,
priv
=
{};
spec
=
spec
||
{};
// Attributes //
priv
.
id
=
spec
.
id
;
priv
.
interval_id
=
null
;
priv
.
interval
=
200
;
priv
.
job_array
=
[];
// Methods //
/**
* Get the job array name in the localStorage
* @method getJobArrayName
* @return {string} The job array name
*/
priv
.
getJobArrayName
=
function
()
{
return
job_array_name
+
'
/
'
+
priv
.
id
;
};
/**
* Returns the job array from the localStorage
* @method getJobArray
* @return {array} The job array.
*/
priv
.
getJobArray
=
function
()
{
return
localstorage
.
getItem
(
priv
.
getJobArrayName
())
||
[];
};
/**
* Does a backup of the job array in the localStorage.
* @method copyJobArrayToLocal
*/
priv
.
copyJobArrayToLocal
=
function
()
{
var
new_a
=
[],
i
;
for
(
i
=
0
;
i
<
priv
.
job_array
.
length
;
i
+=
1
)
{
new_a
.
push
(
priv
.
job_array
[
i
].
serialized
());
}
localstorage
.
setItem
(
priv
.
getJobArrayName
(),
new_a
);
};
/**
* Removes a job from the current job array.
* @method removeJob
* @param {object} job The job object.
*/
priv
.
removeJob
=
function
(
job
)
{
var
i
,
tmp_job_array
=
[];
for
(
i
=
0
;
i
<
priv
.
job_array
.
length
;
i
+=
1
)
{
if
(
priv
.
job_array
[
i
]
!==
job
)
{
tmp_job_array
.
push
(
priv
.
job_array
[
i
]);
}
}
priv
.
job_array
=
tmp_job_array
;
priv
.
copyJobArrayToLocal
();
};
/**
* Sets the job manager id.
* @method setId
* @param {number} id The id.
*/
that
.
setId
=
function
(
id
)
{
priv
.
id
=
id
;
};
/**
* Starts listening to the job array, executing them regulary.
* @method start
*/
that
.
start
=
function
()
{
var
i
;
if
(
priv
.
interval_id
===
null
)
{
priv
.
interval_id
=
setInterval
(
function
()
{
priv
.
restoreOldJio
();
for
(
i
=
0
;
i
<
priv
.
job_array
.
length
;
i
+=
1
)
{
that
.
execute
(
priv
.
job_array
[
i
]);
}
},
priv
.
interval
);
}
};
/**
* Stops listening to the job array.
* @method stop
*/
that
.
stop
=
function
()
{
if
(
priv
.
interval_id
!==
null
)
{
clearInterval
(
priv
.
interval_id
);
priv
.
interval_id
=
null
;
if
(
priv
.
job_array
.
length
===
0
)
{
localstorage
.
removeItem
(
priv
.
getJobArrayName
());
}
}
};
/**
* Try to restore an the inactive older jio instances.
* It will restore the on going or initial jobs from their job array
* and it will add them to this job array.
* @method restoreOldJio
*/
priv
.
restoreOldJio
=
function
()
{
var
i
,
jio_id_a
;
priv
.
lastrestore
=
priv
.
lastrestore
||
0
;
if
(
priv
.
lastrestore
>
(
Date
.
now
())
-
2000
)
{
return
;
}
jio_id_a
=
localstorage
.
getItem
(
'
jio/id_array
'
)
||
[];
for
(
i
=
0
;
i
<
jio_id_a
.
length
;
i
+=
1
)
{
priv
.
restoreOldJioId
(
jio_id_a
[
i
]);
}
priv
.
lastrestore
=
Date
.
now
();
};
/**
* Try to restore an old jio according to an id.
* @method restoreOldJioId
* @param {number} id The jio id.
*/
priv
.
restoreOldJioId
=
function
(
id
)
{
var
jio_date
;
jio_date
=
localstorage
.
getItem
(
'
jio/id/
'
+
id
)
||
0
;
if
(
new
Date
(
jio_date
).
getTime
()
<
(
Date
.
now
()
-
10000
))
{
// 10 sec
priv
.
restoreOldJobFromJioId
(
id
);
priv
.
removeOldJioId
(
id
);
priv
.
removeJobArrayFromJioId
(
id
);
}
};
/**
* Try to restore all jobs from another jio according to an id.
* @method restoreOldJobFromJioId
* @param {number} id The jio id.
*/
priv
.
restoreOldJobFromJioId
=
function
(
id
)
{
var
i
,
command_object
,
jio_job_array
;
jio_job_array
=
localstorage
.
getItem
(
'
jio/job_array/
'
+
id
)
||
[];
for
(
i
=
0
;
i
<
jio_job_array
.
length
;
i
+=
1
)
{
command_object
=
command
(
jio_job_array
[
i
].
command
);
if
(
command_object
.
canBeRestored
())
{
that
.
addJob
(
job
({
storage
:
that
.
storage
(
jio_job_array
[
i
].
storage
),
command
:
command_object
}));
}
}
};
/**
* Removes a jio instance according to an id.
* @method removeOldJioId
* @param {number} id The jio id.
*/
priv
.
removeOldJioId
=
function
(
id
)
{
var
i
,
jio_id_array
,
new_array
=
[];
jio_id_array
=
localstorage
.
getItem
(
'
jio/id_array
'
)
||
[];
for
(
i
=
0
;
i
<
jio_id_array
.
length
;
i
+=
1
)
{
if
(
jio_id_array
[
i
]
!==
id
)
{
new_array
.
push
(
jio_id_array
[
i
]);
}
}
localstorage
.
setItem
(
'
jio/id_array
'
,
new_array
);
localstorage
.
removeItem
(
'
jio/id/
'
+
id
);
};
/**
* Removes a job array from a jio instance according to an id.
* @method removeJobArrayFromJioId
* @param {number} id The jio id.
*/
priv
.
removeJobArrayFromJioId
=
function
(
id
)
{
localstorage
.
removeItem
(
'
jio/job_array/
'
+
id
);
};
/**
* Executes a job.
* @method execute
* @param {object} job The job object.
*/
that
.
execute
=
function
(
job
)
{
try
{
job
.
execute
();
}
catch
(
e
)
{
switch
(
e
.
name
)
{
case
'
jobNotReadyException
'
:
break
;
// do nothing
case
'
tooMuchTriesJobException
'
:
break
;
// do nothing
default
:
throw
e
;
}
}
priv
.
copyJobArrayToLocal
();
};
/**
* Checks if a job exists in the job array according to a job id.
* @method jobIdExists
* @param {number} id The job id.
* @return {boolean} true if exists, else false.
*/
that
.
jobIdExists
=
function
(
id
)
{
var
i
;
for
(
i
=
0
;
i
<
priv
.
job_array
.
length
;
i
+=
1
)
{
if
(
priv
.
job_array
[
i
].
getId
()
===
id
)
{
return
true
;
}
}
return
false
;
};
/**
* Terminate a job. It only remove it from the job array.
* @method terminateJob
* @param {object} job The job object
*/
that
.
terminateJob
=
function
(
job
)
{
priv
.
removeJob
(
job
);
};
/**
* Adds a job to the current job array.
* @method addJob
* @param {object} job The new job.
*/
that
.
addJob
=
function
(
job
)
{
var
result_array
=
that
.
validateJobAccordingToJobList
(
priv
.
job_array
,
job
);
priv
.
appendJob
(
job
,
result_array
);
};
/**
* Generate a result array containing action string to do with the good job.
* @method validateJobAccordingToJobList
* @param {array} job_array A job array.
* @param {object} job The new job to compare with.
* @return {array} A result array.
*/
that
.
validateJobAccordingToJobList
=
function
(
job_array
,
job
)
{
var
i
,
result_array
=
[];
for
(
i
=
0
;
i
<
job_array
.
length
;
i
+=
1
)
{
result_array
.
push
(
jobRules
.
validateJobAccordingToJob
(
job_array
[
i
],
job
));
}
return
result_array
;
};
/**
* It will manage the job in order to know what to do thanks to a result
* array. The new job can be added to the job array, but it can also be
* not accepted. It is this method which can tells jobs to wait for another
* one, to replace one or to eliminate some while browsing.
* @method appendJob
* @param {object} job The job to append.
* @param {array} result_array The result array.
*/
priv
.
appendJob
=
function
(
job
,
result_array
)
{
var
i
;
if
(
priv
.
job_array
.
length
!==
result_array
.
length
)
{
throw
new
RangeError
(
"
Array out of bound
"
);
}
for
(
i
=
0
;
i
<
result_array
.
length
;
i
+=
1
)
{
if
(
result_array
[
i
].
action
===
'
dont accept
'
)
{
return
job
.
notAccepted
();
}
}
for
(
i
=
0
;
i
<
result_array
.
length
;
i
+=
1
)
{
switch
(
result_array
[
i
].
action
)
{
case
'
eliminate
'
:
result_array
[
i
].
job
.
eliminated
();
priv
.
removeJob
(
result_array
[
i
].
job
);
break
;
case
'
update
'
:
result_array
[
i
].
job
.
update
(
job
);
priv
.
copyJobArrayToLocal
();
return
;
case
'
wait
'
:
job
.
waitForJob
(
result_array
[
i
].
job
);
break
;
default
:
break
;
}
}
priv
.
job_array
.
push
(
job
);
priv
.
copyJobArrayToLocal
();
};
that
.
serialized
=
function
()
{
var
a
=
[],
i
,
job_array
=
priv
.
job_array
||
[];
for
(
i
=
0
;
i
<
job_array
.
length
;
i
+=
1
)
{
a
.
push
(
job_array
[
i
].
serialized
());
}
return
a
;
};
return
that
;
}());
/*jslint indent: 2, maxlen: 80, sloppy: true */
var
jobRules
=
(
function
()
{
var
that
=
{},
priv
=
{};
priv
.
compare
=
{};
priv
.
action
=
{};
Object
.
defineProperty
(
that
,
"
eliminate
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
'
eliminate
'
;
}
});
Object
.
defineProperty
(
that
,
"
update
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
'
update
'
;
}
});
Object
.
defineProperty
(
that
,
"
dontAccept
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
'
dont accept
'
;
}
});
Object
.
defineProperty
(
that
,
"
wait
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
'
wait
'
;
}
});
Object
.
defineProperty
(
that
,
"
none
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
'
none
'
;
}
});
that
.
default_action
=
that
.
none
;
that
.
default_compare
=
function
(
job1
,
job2
)
{
return
(
job1
.
getCommand
().
getDocId
()
===
job2
.
getCommand
().
getDocId
()
&&
job1
.
getCommand
().
getDocInfo
(
'
_rev
'
)
===
job2
.
getCommand
().
getDocInfo
(
'
_rev
'
)
&&
job1
.
getCommand
().
getOption
(
'
rev
'
)
===
job2
.
getCommand
().
getOption
(
'
rev
'
)
&&
JSON
.
stringify
(
job1
.
getStorage
().
serialized
())
===
JSON
.
stringify
(
job2
.
getStorage
().
serialized
()));
};
// Methods //
/**
* Returns an action according the jobs given in parameters.
* @method getAction
* @param {object} job1 The already existant job.
* @param {object} job2 The job to compare with.
* @return {string} An action string.
*/
priv
.
getAction
=
function
(
job1
,
job2
)
{
var
j1label
,
j2label
,
j1status
;
j1label
=
job1
.
getCommand
().
getLabel
();
j2label
=
job2
.
getCommand
().
getLabel
();
j1status
=
(
job1
.
getStatus
().
getLabel
()
===
'
on going
'
?
'
on going
'
:
'
not on going
'
);
if
(
priv
.
action
[
j1label
]
&&
priv
.
action
[
j1label
][
j1status
]
&&
priv
.
action
[
j1label
][
j1status
][
j2label
])
{
return
priv
.
action
[
j1label
][
j1status
][
j2label
](
job1
,
job2
);
}
return
that
.
default_action
(
job1
,
job2
);
};
/**
* Checks if the two jobs are comparable.
* @method canCompare
* @param {object} job1 The already existant job.
* @param {object} job2 The job to compare with.
* @return {boolean} true if comparable, else false.
*/
priv
.
canCompare
=
function
(
job1
,
job2
)
{
var
job1label
=
job1
.
getCommand
().
getLabel
(),
job2label
=
job2
.
getCommand
().
getLabel
();
if
(
priv
.
compare
[
job1label
]
&&
priv
.
compare
[
job2label
])
{
return
priv
.
compare
[
job1label
][
job2label
](
job1
,
job2
);
}
return
that
.
default_compare
(
job1
,
job2
);
};
/**
* Returns an action string to show what to do if we want to add a job.
* @method validateJobAccordingToJob
* @param {object} job1 The current job.
* @param {object} job2 The new job.
* @return {string} The action string.
*/
Object
.
defineProperty
(
that
,
"
validateJobAccordingToJob
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
job1
,
job2
)
{
if
(
priv
.
canCompare
(
job1
,
job2
))
{
return
{
action
:
priv
.
getAction
(
job1
,
job2
),
job
:
job1
};
}
return
{
action
:
that
.
default_action
(
job1
,
job2
),
job
:
job1
};
}
});
/**
* Adds a rule the action rules.
* @method addActionRule
* @param {string} method1 The action label from the current job.
* @param {boolean} ongoing Is this action is on going or not?
* @param {string} method2 The action label from the new job.
* @param {function} rule The rule that return an action string.
*/
Object
.
defineProperty
(
that
,
"
addActionRule
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
method1
,
ongoing
,
method2
,
rule
)
{
var
ongoing_s
=
(
ongoing
?
'
on going
'
:
'
not on going
'
);
priv
.
action
[
method1
]
=
priv
.
action
[
method1
]
||
{};
priv
.
action
[
method1
][
ongoing_s
]
=
priv
.
action
[
method1
][
ongoing_s
]
||
{};
priv
.
action
[
method1
][
ongoing_s
][
method2
]
=
rule
;
}
});
/**
* Adds a rule the compare rules.
* @method addCompareRule
* @param {string} method1 The action label from the current job.
* @param {string} method2 The action label from the new job.
* @param {function} rule The rule that return a boolean
* - true if job1 and job2 can be compared, else false.
*/
Object
.
defineProperty
(
that
,
"
addCompareRule
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
method1
,
method2
,
rule
)
{
priv
.
compare
[
method1
]
=
priv
.
compare
[
method1
]
||
{};
priv
.
compare
[
method1
][
method2
]
=
rule
;
}
});
////////////////////////////////////////////////////////////////////////////
// Adding some rules
/*
LEGEND:
- s: storage
- m: method
- n: name
- c: content
- o: options
- =: are equal
- !: are not equal
select ALL s= n=
removefailordone fail|done
/ elim repl nacc wait
Remove !ongoing Save 1 x x x
Save !ongoing Remove 1 x x x
GetList !ongoing GetList 0 1 x x
Remove !ongoing Remove 0 1 x x
Load !ongoing Load 0 1 x x
Save c= !ongoing Save 0 1 x x
Save c! !ongoing Save 0 1 x x
GetList ongoing GetList 0 0 1 x
Remove ongoing Remove 0 0 1 x
Remove ongoing Load 0 0 1 x
Remove !ongoing Load 0 0 1 x
Load ongoing Load 0 0 1 x
Save c= ongoing Save 0 0 1 x
Remove ongoing Save 0 0 0 1
Load ongoing Remove 0 0 0 1
Load ongoing Save 0 0 0 1
Load !ongoing Remove 0 0 0 1
Load !ongoing Save 0 0 0 1
Save ongoing Remove 0 0 0 1
Save ongoing Load 0 0 0 1
Save c! ongoing Save 0 0 0 1
Save !ongoing Load 0 0 0 1
GetList ongoing Remove 0 0 0 0
GetList ongoing Load 0 0 0 0
GetList ongoing Save 0 0 0 0
GetList !ongoing Remove 0 0 0 0
GetList !ongoing Load 0 0 0 0
GetList !ongoing Save 0 0 0 0
Remove ongoing GetList 0 0 0 0
Remove !ongoing GetList 0 0 0 0
Load ongoing GetList 0 0 0 0
Load !ongoing GetList 0 0 0 0
Save ongoing GetList 0 0 0 0
Save !ongoing GetList 0 0 0 0
For more information, see documentation
*/
that
.
addActionRule
(
'
post
'
,
true
,
'
post
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
post
'
,
true
,
'
put
'
,
that
.
wait
);
that
.
addActionRule
(
'
post
'
,
true
,
'
get
'
,
that
.
wait
);
that
.
addActionRule
(
'
post
'
,
true
,
'
remove
'
,
that
.
wait
);
that
.
addActionRule
(
'
post
'
,
true
,
'
putAttachment
'
,
that
.
wait
);
that
.
addActionRule
(
'
post
'
,
false
,
'
post
'
,
that
.
update
);
that
.
addActionRule
(
'
post
'
,
false
,
'
put
'
,
that
.
wait
);
that
.
addActionRule
(
'
post
'
,
false
,
'
get
'
,
that
.
wait
);
that
.
addActionRule
(
'
post
'
,
false
,
'
remove
'
,
that
.
eliminate
);
that
.
addActionRule
(
'
post
'
,
false
,
'
putAttachment
'
,
that
.
wait
);
that
.
addActionRule
(
'
put
'
,
true
,
'
post
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
put
'
,
true
,
'
put
'
,
that
.
wait
);
that
.
addActionRule
(
'
put
'
,
true
,
'
get
'
,
that
.
wait
);
that
.
addActionRule
(
'
put
'
,
true
,
'
remove
'
,
that
.
wait
);
that
.
addActionRule
(
'
put
'
,
true
,
'
putAttachment
'
,
that
.
wait
);
that
.
addActionRule
(
'
put
'
,
false
,
'
post
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
put
'
,
false
,
'
put
'
,
that
.
update
);
that
.
addActionRule
(
'
put
'
,
false
,
'
get
'
,
that
.
wait
);
that
.
addActionRule
(
'
put
'
,
false
,
'
remove
'
,
that
.
eliminate
);
that
.
addActionRule
(
'
put
'
,
false
,
'
putAttachment
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
true
,
'
post
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
true
,
'
put
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
true
,
'
get
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
get
'
,
true
,
'
remove
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
true
,
'
putAttachment
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
false
,
'
post
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
false
,
'
put
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
false
,
'
get
'
,
that
.
update
);
that
.
addActionRule
(
'
get
'
,
false
,
'
remove
'
,
that
.
wait
);
that
.
addActionRule
(
'
get
'
,
false
,
'
putAttachment
'
,
that
.
wait
);
that
.
addActionRule
(
'
remove
'
,
true
,
'
post
'
,
that
.
wait
);
that
.
addActionRule
(
'
remove
'
,
true
,
'
get
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
remove
'
,
true
,
'
remove
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
remove
'
,
true
,
'
putAttachment
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
remove
'
,
false
,
'
post
'
,
that
.
eliminate
);
that
.
addActionRule
(
'
remove
'
,
false
,
'
put
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
remove
'
,
false
,
'
get
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
remove
'
,
false
,
'
remove
'
,
that
.
update
);
that
.
addActionRule
(
'
remove
'
,
false
,
'
putAttachment
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
allDocs
'
,
true
,
'
allDocs
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
allDocs
'
,
false
,
'
allDocs
'
,
that
.
update
);
that
.
addActionRule
(
'
putAttachment
'
,
true
,
'
post
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
putAttachment
'
,
true
,
'
put
'
,
that
.
wait
);
that
.
addActionRule
(
'
putAttachment
'
,
true
,
'
get
'
,
that
.
wait
);
that
.
addActionRule
(
'
putAttachment
'
,
true
,
'
remove
'
,
that
.
wait
);
that
.
addActionRule
(
'
putAttachment
'
,
true
,
'
putAttachment
'
,
that
.
wait
);
that
.
addActionRule
(
'
putAttachment
'
,
false
,
'
post
'
,
that
.
dontAccept
);
that
.
addActionRule
(
'
putAttachment
'
,
false
,
'
put
'
,
that
.
wait
);
that
.
addActionRule
(
'
putAttachment
'
,
false
,
'
get
'
,
that
.
wait
);
that
.
addActionRule
(
'
putAttachment
'
,
false
,
'
remove
'
,
that
.
eliminate
);
that
.
addActionRule
(
'
putAttachment
'
,
false
,
'
putAttachment
'
,
that
.
update
);
// end adding rules
////////////////////////////////////////////////////////////////////////////
return
that
;
}());
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global spec: true, localstorage: true,
activityUpdater: true, jobManager: true, storage: true,
storage_type_object: true, invalidStorageType: true, jobRules: true,
job: true, postCommand: true, putCommand: true, getCommand:true,
allDocsCommand: true, putAttachmentCommand: true,
removeCommand: true */
// Class jio
var
that
=
{},
priv
=
{},
jio_id_array_name
=
'
jio/id_array
'
;
spec
=
spec
||
{};
// Attributes //
priv
.
id
=
null
;
priv
.
storage_spec
=
spec
;
priv
.
environments
=
{};
// initialize //
priv
.
init
=
function
()
{
// Initialize the jio id and add the new id to the list
if
(
priv
.
id
===
null
)
{
var
i
,
jio_id_a
=
localstorage
.
getItem
(
jio_id_array_name
)
||
[];
priv
.
id
=
1
;
for
(
i
=
0
;
i
<
jio_id_a
.
length
;
i
+=
1
)
{
if
(
jio_id_a
[
i
]
>=
priv
.
id
)
{
priv
.
id
=
jio_id_a
[
i
]
+
1
;
}
}
jio_id_a
.
push
(
priv
.
id
);
localstorage
.
setItem
(
jio_id_array_name
,
jio_id_a
);
activityUpdater
.
setId
(
priv
.
id
);
jobManager
.
setId
(
priv
.
id
);
}
};
// Methods //
/**
* Returns a storage from a storage description.
* @method storage
* @param {object} spec The specifications.
* @param {object} my The protected object.
* @param {string} forcetype Force storage type
* @return {object} The storage object.
*/
Object
.
defineProperty
(
that
,
"
storage
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
spec
,
my
,
forcetype
)
{
var
spec_str
,
type
;
spec
=
spec
||
{};
my
=
my
||
{};
my
.
basicStorage
=
storage
;
spec_str
=
JSON
.
stringify
(
spec
);
// environment initialization
priv
.
environments
[
spec_str
]
=
priv
.
environments
[
spec_str
]
||
{};
my
.
env
=
priv
.
environments
[
spec_str
];
my
.
storage
=
that
.
storage
;
// NOTE : or proxy storage
type
=
forcetype
||
spec
.
type
||
'
base
'
;
if
(
type
===
'
base
'
)
{
return
storage
(
spec
,
my
);
}
if
(
!
storage_type_object
[
type
])
{
throw
invalidStorageType
({
"
type
"
:
type
,
"
message
"
:
"
Storage does not exists.
"
});
}
return
storage_type_object
[
type
](
spec
,
my
);
}
});
jobManager
.
storage
=
that
.
storage
;
Object
.
defineProperty
(
that
,
"
start
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
priv
.
init
();
activityUpdater
.
start
();
jobManager
.
start
();
}
});
Object
.
defineProperty
(
that
,
"
stop
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
jobManager
.
stop
();
}
});
Object
.
defineProperty
(
that
,
"
close
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
activityUpdater
.
stop
();
jobManager
.
stop
();
priv
.
id
=
null
;
}
});
/**
* Returns the jio id.
* @method getId
* @return {number} The jio id.
*/
Object
.
defineProperty
(
that
,
"
getId
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
priv
.
id
;
}
});
/**
* Returns the jio job rules object used by the job manager.
* @method getJobRules
* @return {object} The job rules object
*/
Object
.
defineProperty
(
that
,
"
getJobRules
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
jobRules
;
}
});
/**
* Checks if the storage description is valid or not.
* @method validateStorageDescription
* @param {object} description The description object.
* @return {boolean} true if ok, else false.
*/
Object
.
defineProperty
(
that
,
"
validateStorageDescription
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
description
)
{
return
that
.
storage
(
description
).
isValid
();
}
});
Object
.
defineProperty
(
that
,
"
getJobArray
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
()
{
return
jobManager
.
serialized
();
}
});
priv
.
makeCallbacks
=
function
(
param
,
callback1
,
callback2
)
{
param
.
callback
=
function
(
err
,
val
)
{
if
(
err
)
{
param
.
error
(
err
);
}
else
{
param
.
success
(
val
);
}
};
param
.
success
=
function
(
val
)
{
param
.
callback
(
undefined
,
val
);
};
param
.
error
=
function
(
err
)
{
param
.
callback
(
err
,
undefined
);
};
if
(
typeof
callback1
===
'
function
'
)
{
if
(
typeof
callback2
===
'
function
'
)
{
param
.
success
=
callback1
;
param
.
error
=
callback2
;
}
else
{
param
.
callback
=
callback1
;
}
}
else
{
param
.
callback
=
function
()
{};
}
};
priv
.
parametersToObject
=
function
(
list
,
default_options
)
{
var
k
,
i
=
0
,
callbacks
=
[],
param
=
{
"
options
"
:
{}};
for
(
i
=
0
;
i
<
list
.
length
;
i
+=
1
)
{
if
(
typeof
list
[
i
]
===
'
object
'
)
{
// this is the option
param
.
options
=
list
[
i
];
for
(
k
in
default_options
)
{
if
((
typeof
default_options
[
k
])
!==
(
typeof
list
[
i
][
k
]))
{
param
.
options
[
k
]
=
default_options
[
k
];
}
}
}
if
(
typeof
list
[
i
]
===
'
function
'
)
{
// this is a callback
callbacks
.
push
(
list
[
i
]);
}
}
priv
.
makeCallbacks
(
param
,
callbacks
[
0
],
callbacks
[
1
]);
return
param
;
};
priv
.
addJob
=
function
(
commandCreator
,
spec
)
{
jobManager
.
addJob
(
job
({
"
storage
"
:
that
.
storage
(
priv
.
storage_spec
),
"
command
"
:
commandCreator
(
spec
)
}));
};
/**
* Post a document.
* @method post
* @param {object} doc The document object. Contains at least:
* - {string} _id The document id (optional), "/" are forbidden
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} revs Include revision history of the document.
* - {boolean} revs_info Retreive the revisions.
* - {boolean} conflicts Retreive the conflict list.
* @param {function} callback (optional) The callback(err,response).
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
post
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
doc
,
options
,
success
,
error
)
{
var
param
=
priv
.
parametersToObject
(
[
options
,
success
,
error
],
{
max_retry
:
0
}
);
priv
.
addJob
(
postCommand
,
{
doc
:
doc
,
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
/**
* Put a document.
* @method put
* @param {object} doc The document object. Contains at least:
* - {string} _id The document id, "/" are forbidden
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} revs Include revision history of the document.
* - {boolean} revs_info Retreive the revisions.
* - {boolean} conflicts Retreive the conflict list.
* @param {function} callback (optional) The callback(err,response).
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
put
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
doc
,
options
,
success
,
error
)
{
var
param
=
priv
.
parametersToObject
(
[
options
,
success
,
error
],
{
max_retry
:
0
}
);
priv
.
addJob
(
putCommand
,
{
doc
:
doc
,
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
/**
* Get a document.
* @method get
* @param {string} docid The document id: "doc_id" or "doc_id/attachmt_id".
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* - {string} rev The revision we want to get.
* - {boolean} revs Include revision history of the document.
* - {boolean} revs_info Include list of revisions, and their availability.
* - {boolean} conflicts Include a list of conflicts.
* @param {function} callback (optional) The callback(err,response).
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
get
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
id
,
options
,
success
,
error
)
{
var
param
=
priv
.
parametersToObject
(
[
options
,
success
,
error
],
{
max_retry
:
3
}
);
priv
.
addJob
(
getCommand
,
{
docid
:
id
,
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
/**
* Remove a document.
* @method remove
* @param {object} doc The document object. Contains at least:
* - {string} _id The document id: "doc_id" or "doc_id/attachment_id"
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} revs Include revision history of the document.
* - {boolean} revs_info Include list of revisions, and their availability.
* - {boolean} conflicts Include a list of conflicts.
* @param {function} callback (optional) The callback(err,response).
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
remove
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
doc
,
options
,
success
,
callback
)
{
var
param
=
priv
.
parametersToObject
(
[
options
,
success
,
callback
],
{
max_retry
:
0
}
);
priv
.
addJob
(
removeCommand
,
{
doc
:
doc
,
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
/**
* Get a list of documents.
* @method allDocs
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} include_docs Include document metadata
* - {boolean} revs Include revision history of the document.
* - {boolean} revs_info Include revisions.
* - {boolean} conflicts Include conflicts.
* @param {function} callback (optional) The callback(err,response).
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
allDocs
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
options
,
success
,
error
)
{
var
param
=
priv
.
parametersToObject
(
[
options
,
success
,
error
],
{
max_retry
:
3
}
);
priv
.
addJob
(
allDocsCommand
,
{
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
/**
* Put an attachment to a document.
* @method putAttachment
* @param {object} doc The document object. Contains at least:
* - {string} id The document id: "doc_id/attchment_id"
* - {string} data Base64 attachment data
* - {string} mimetype The attachment mimetype
* - {string} rev The attachment revision
* @param {object} options (optional) Contains some options:
* - {number} max_retry The number max of retries, 0 = infinity.
* - {boolean} revs Include revision history of the document.
* - {boolean} revs_info Include revisions.
* - {boolean} conflicts Include conflicts.
* @param {function} callback (optional) The callback(err,respons)
* @param {function} error (optional) The callback on error, if this
* callback is given in parameter, "callback" is changed as "success",
* called on success.
*/
Object
.
defineProperty
(
that
,
"
putAttachment
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
doc
,
options
,
success
,
error
)
{
var
param
,
k
,
doc_with_underscores
=
{};
param
=
priv
.
parametersToObject
(
[
options
,
success
,
error
],
{
max_retry
:
0
}
);
for
(
k
in
doc
)
{
if
(
doc
.
hasOwnProperty
(
k
)
&&
k
.
match
(
'
[^_].*
'
))
{
doc_with_underscores
[
"
_
"
+
k
]
=
doc
[
k
];
}
}
priv
.
addJob
(
putAttachmentCommand
,
{
doc
:
doc_with_underscores
,
options
:
param
.
options
,
callbacks
:
{
success
:
param
.
success
,
error
:
param
.
error
}
});
}
});
return
that
;
};
// End Class jio
/*jslint indent: 2, maxlen: 80, sloppy: true */
/*global jio: true, invalidStorageType: true */
var
storage_type_object
=
{
// -> 'key':constructorFunction
'
base
'
:
function
()
{}
// overriden by jio
};
var
jioNamespace
=
(
function
(
spec
)
{
var
that
=
{};
spec
=
spec
||
{};
// Attributes //
// Methods //
/**
* Creates a new jio instance.
* @method newJio
* @param {object} spec The storage description
* @return {object} The new Jio instance.
*/
Object
.
defineProperty
(
that
,
"
newJio
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
spec
)
{
var
storage
=
spec
,
instance
=
null
;
if
(
typeof
storage
===
'
string
'
)
{
storage
=
JSON
.
parse
(
storage
);
}
else
{
storage
=
JSON
.
stringify
(
storage
);
if
(
storage
!==
undefined
)
{
storage
=
JSON
.
parse
(
storage
);
}
}
storage
=
storage
||
{
type
:
'
base
'
};
instance
=
jio
(
storage
);
instance
.
start
();
return
instance
;
}
});
/**
* Add a storage type to jio.
* @method addStorageType
* @param {string} type The storage type
* @param {function} constructor The associated constructor
*/
Object
.
defineProperty
(
that
,
"
addStorageType
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
function
(
type
,
constructor
)
{
constructor
=
constructor
||
function
()
{
return
null
;
};
if
(
storage_type_object
[
type
])
{
throw
invalidStorageType
({
type
:
type
,
message
:
'
Already known.
'
});
}
storage_type_object
[
type
]
=
constructor
;
}
});
return
that
;
}());
Object
.
defineProperty
(
scope
,
"
jIO
"
,
{
configurable
:
false
,
enumerable
:
false
,
writable
:
false
,
value
:
jioNamespace
});
}(
window
,
hex_md5
));
lib/jio/md5.js
0 → 100644
View file @
720d75aa
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var
hexcase
=
0
;
/* hex output format. 0 - lowercase; 1 - uppercase */
var
b64pad
=
""
;
/* base-64 pad character. "=" for strict RFC compliance */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function
hex_md5
(
s
)
{
return
rstr2hex
(
rstr_md5
(
str2rstr_utf8
(
s
)));
}
function
b64_md5
(
s
)
{
return
rstr2b64
(
rstr_md5
(
str2rstr_utf8
(
s
)));
}
function
any_md5
(
s
,
e
)
{
return
rstr2any
(
rstr_md5
(
str2rstr_utf8
(
s
)),
e
);
}
function
hex_hmac_md5
(
k
,
d
)
{
return
rstr2hex
(
rstr_hmac_md5
(
str2rstr_utf8
(
k
),
str2rstr_utf8
(
d
)));
}
function
b64_hmac_md5
(
k
,
d
)
{
return
rstr2b64
(
rstr_hmac_md5
(
str2rstr_utf8
(
k
),
str2rstr_utf8
(
d
)));
}
function
any_hmac_md5
(
k
,
d
,
e
)
{
return
rstr2any
(
rstr_hmac_md5
(
str2rstr_utf8
(
k
),
str2rstr_utf8
(
d
)),
e
);
}
/*
* Perform a simple self-test to see if the VM is working
*/
function
md5_vm_test
()
{
return
hex_md5
(
"
abc
"
).
toLowerCase
()
==
"
900150983cd24fb0d6963f7d28e17f72
"
;
}
/*
* Calculate the MD5 of a raw string
*/
function
rstr_md5
(
s
)
{
return
binl2rstr
(
binl_md5
(
rstr2binl
(
s
),
s
.
length
*
8
));
}
/*
* Calculate the HMAC-MD5, of a key and some data (raw strings)
*/
function
rstr_hmac_md5
(
key
,
data
)
{
var
bkey
=
rstr2binl
(
key
);
if
(
bkey
.
length
>
16
)
bkey
=
binl_md5
(
bkey
,
key
.
length
*
8
);
var
ipad
=
Array
(
16
),
opad
=
Array
(
16
);
for
(
var
i
=
0
;
i
<
16
;
i
++
)
{
ipad
[
i
]
=
bkey
[
i
]
^
0x36363636
;
opad
[
i
]
=
bkey
[
i
]
^
0x5C5C5C5C
;
}
var
hash
=
binl_md5
(
ipad
.
concat
(
rstr2binl
(
data
)),
512
+
data
.
length
*
8
);
return
binl2rstr
(
binl_md5
(
opad
.
concat
(
hash
),
512
+
128
));
}
/*
* Convert a raw string to a hex string
*/
function
rstr2hex
(
input
)
{
try
{
hexcase
}
catch
(
e
)
{
hexcase
=
0
;
}
var
hex_tab
=
hexcase
?
"
0123456789ABCDEF
"
:
"
0123456789abcdef
"
;
var
output
=
""
;
var
x
;
for
(
var
i
=
0
;
i
<
input
.
length
;
i
++
)
{
x
=
input
.
charCodeAt
(
i
);
output
+=
hex_tab
.
charAt
((
x
>>>
4
)
&
0x0F
)
+
hex_tab
.
charAt
(
x
&
0x0F
);
}
return
output
;
}
/*
* Convert a raw string to a base-64 string
*/
function
rstr2b64
(
input
)
{
try
{
b64pad
}
catch
(
e
)
{
b64pad
=
''
;
}
var
tab
=
"
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
"
;
var
output
=
""
;
var
len
=
input
.
length
;
for
(
var
i
=
0
;
i
<
len
;
i
+=
3
)
{
var
triplet
=
(
input
.
charCodeAt
(
i
)
<<
16
)
|
(
i
+
1
<
len
?
input
.
charCodeAt
(
i
+
1
)
<<
8
:
0
)
|
(
i
+
2
<
len
?
input
.
charCodeAt
(
i
+
2
)
:
0
);
for
(
var
j
=
0
;
j
<
4
;
j
++
)
{
if
(
i
*
8
+
j
*
6
>
input
.
length
*
8
)
output
+=
b64pad
;
else
output
+=
tab
.
charAt
((
triplet
>>>
6
*
(
3
-
j
))
&
0x3F
);
}
}
return
output
;
}
/*
* Convert a raw string to an arbitrary string encoding
*/
function
rstr2any
(
input
,
encoding
)
{
var
divisor
=
encoding
.
length
;
var
i
,
j
,
q
,
x
,
quotient
;
/* Convert to an array of 16-bit big-endian values, forming the dividend */
var
dividend
=
Array
(
Math
.
ceil
(
input
.
length
/
2
));
for
(
i
=
0
;
i
<
dividend
.
length
;
i
++
)
{
dividend
[
i
]
=
(
input
.
charCodeAt
(
i
*
2
)
<<
8
)
|
input
.
charCodeAt
(
i
*
2
+
1
);
}
/*
* Repeatedly perform a long division. The binary array forms the dividend,
* the length of the encoding is the divisor. Once computed, the quotient
* forms the dividend for the next step. All remainders are stored for later
* use.
*/
var
full_length
=
Math
.
ceil
(
input
.
length
*
8
/
(
Math
.
log
(
encoding
.
length
)
/
Math
.
log
(
2
)));
var
remainders
=
Array
(
full_length
);
for
(
j
=
0
;
j
<
full_length
;
j
++
)
{
quotient
=
Array
();
x
=
0
;
for
(
i
=
0
;
i
<
dividend
.
length
;
i
++
)
{
x
=
(
x
<<
16
)
+
dividend
[
i
];
q
=
Math
.
floor
(
x
/
divisor
);
x
-=
q
*
divisor
;
if
(
quotient
.
length
>
0
||
q
>
0
)
quotient
[
quotient
.
length
]
=
q
;
}
remainders
[
j
]
=
x
;
dividend
=
quotient
;
}
/* Convert the remainders to the output string */
var
output
=
""
;
for
(
i
=
remainders
.
length
-
1
;
i
>=
0
;
i
--
)
output
+=
encoding
.
charAt
(
remainders
[
i
]);
return
output
;
}
/*
* Encode a string as utf-8.
* For efficiency, this assumes the input is valid utf-16.
*/
function
str2rstr_utf8
(
input
)
{
var
output
=
""
;
var
i
=
-
1
;
var
x
,
y
;
while
(
++
i
<
input
.
length
)
{
/* Decode utf-16 surrogate pairs */
x
=
input
.
charCodeAt
(
i
);
y
=
i
+
1
<
input
.
length
?
input
.
charCodeAt
(
i
+
1
)
:
0
;
if
(
0xD800
<=
x
&&
x
<=
0xDBFF
&&
0xDC00
<=
y
&&
y
<=
0xDFFF
)
{
x
=
0x10000
+
((
x
&
0x03FF
)
<<
10
)
+
(
y
&
0x03FF
);
i
++
;
}
/* Encode output as utf-8 */
if
(
x
<=
0x7F
)
output
+=
String
.
fromCharCode
(
x
);
else
if
(
x
<=
0x7FF
)
output
+=
String
.
fromCharCode
(
0xC0
|
((
x
>>>
6
)
&
0x1F
),
0x80
|
(
x
&
0x3F
));
else
if
(
x
<=
0xFFFF
)
output
+=
String
.
fromCharCode
(
0xE0
|
((
x
>>>
12
)
&
0x0F
),
0x80
|
((
x
>>>
6
)
&
0x3F
),
0x80
|
(
x
&
0x3F
));
else
if
(
x
<=
0x1FFFFF
)
output
+=
String
.
fromCharCode
(
0xF0
|
((
x
>>>
18
)
&
0x07
),
0x80
|
((
x
>>>
12
)
&
0x3F
),
0x80
|
((
x
>>>
6
)
&
0x3F
),
0x80
|
(
x
&
0x3F
));
}
return
output
;
}
/*
* Encode a string as utf-16
*/
function
str2rstr_utf16le
(
input
)
{
var
output
=
""
;
for
(
var
i
=
0
;
i
<
input
.
length
;
i
++
)
output
+=
String
.
fromCharCode
(
input
.
charCodeAt
(
i
)
&
0xFF
,
(
input
.
charCodeAt
(
i
)
>>>
8
)
&
0xFF
);
return
output
;
}
function
str2rstr_utf16be
(
input
)
{
var
output
=
""
;
for
(
var
i
=
0
;
i
<
input
.
length
;
i
++
)
output
+=
String
.
fromCharCode
((
input
.
charCodeAt
(
i
)
>>>
8
)
&
0xFF
,
input
.
charCodeAt
(
i
)
&
0xFF
);
return
output
;
}
/*
* Convert a raw string to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
function
rstr2binl
(
input
)
{
var
output
=
Array
(
input
.
length
>>
2
);
for
(
var
i
=
0
;
i
<
output
.
length
;
i
++
)
output
[
i
]
=
0
;
for
(
var
i
=
0
;
i
<
input
.
length
*
8
;
i
+=
8
)
output
[
i
>>
5
]
|=
(
input
.
charCodeAt
(
i
/
8
)
&
0xFF
)
<<
(
i
%
32
);
return
output
;
}
/*
* Convert an array of little-endian words to a string
*/
function
binl2rstr
(
input
)
{
var
output
=
""
;
for
(
var
i
=
0
;
i
<
input
.
length
*
32
;
i
+=
8
)
output
+=
String
.
fromCharCode
((
input
[
i
>>
5
]
>>>
(
i
%
32
))
&
0xFF
);
return
output
;
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
function
binl_md5
(
x
,
len
)
{
/* append padding */
x
[
len
>>
5
]
|=
0x80
<<
((
len
)
%
32
);
x
[(((
len
+
64
)
>>>
9
)
<<
4
)
+
14
]
=
len
;
var
a
=
1732584193
;
var
b
=
-
271733879
;
var
c
=
-
1732584194
;
var
d
=
271733878
;
for
(
var
i
=
0
;
i
<
x
.
length
;
i
+=
16
)
{
var
olda
=
a
;
var
oldb
=
b
;
var
oldc
=
c
;
var
oldd
=
d
;
a
=
md5_ff
(
a
,
b
,
c
,
d
,
x
[
i
+
0
],
7
,
-
680876936
);
d
=
md5_ff
(
d
,
a
,
b
,
c
,
x
[
i
+
1
],
12
,
-
389564586
);
c
=
md5_ff
(
c
,
d
,
a
,
b
,
x
[
i
+
2
],
17
,
606105819
);
b
=
md5_ff
(
b
,
c
,
d
,
a
,
x
[
i
+
3
],
22
,
-
1044525330
);
a
=
md5_ff
(
a
,
b
,
c
,
d
,
x
[
i
+
4
],
7
,
-
176418897
);
d
=
md5_ff
(
d
,
a
,
b
,
c
,
x
[
i
+
5
],
12
,
1200080426
);
c
=
md5_ff
(
c
,
d
,
a
,
b
,
x
[
i
+
6
],
17
,
-
1473231341
);
b
=
md5_ff
(
b
,
c
,
d
,
a
,
x
[
i
+
7
],
22
,
-
45705983
);
a
=
md5_ff
(
a
,
b
,
c
,
d
,
x
[
i
+
8
],
7
,
1770035416
);
d
=
md5_ff
(
d
,
a
,
b
,
c
,
x
[
i
+
9
],
12
,
-
1958414417
);
c
=
md5_ff
(
c
,
d
,
a
,
b
,
x
[
i
+
10
],
17
,
-
42063
);
b
=
md5_ff
(
b
,
c
,
d
,
a
,
x
[
i
+
11
],
22
,
-
1990404162
);
a
=
md5_ff
(
a
,
b
,
c
,
d
,
x
[
i
+
12
],
7
,
1804603682
);
d
=
md5_ff
(
d
,
a
,
b
,
c
,
x
[
i
+
13
],
12
,
-
40341101
);
c
=
md5_ff
(
c
,
d
,
a
,
b
,
x
[
i
+
14
],
17
,
-
1502002290
);
b
=
md5_ff
(
b
,
c
,
d
,
a
,
x
[
i
+
15
],
22
,
1236535329
);
a
=
md5_gg
(
a
,
b
,
c
,
d
,
x
[
i
+
1
],
5
,
-
165796510
);
d
=
md5_gg
(
d
,
a
,
b
,
c
,
x
[
i
+
6
],
9
,
-
1069501632
);
c
=
md5_gg
(
c
,
d
,
a
,
b
,
x
[
i
+
11
],
14
,
643717713
);
b
=
md5_gg
(
b
,
c
,
d
,
a
,
x
[
i
+
0
],
20
,
-
373897302
);
a
=
md5_gg
(
a
,
b
,
c
,
d
,
x
[
i
+
5
],
5
,
-
701558691
);
d
=
md5_gg
(
d
,
a
,
b
,
c
,
x
[
i
+
10
],
9
,
38016083
);
c
=
md5_gg
(
c
,
d
,
a
,
b
,
x
[
i
+
15
],
14
,
-
660478335
);
b
=
md5_gg
(
b
,
c
,
d
,
a
,
x
[
i
+
4
],
20
,
-
405537848
);
a
=
md5_gg
(
a
,
b
,
c
,
d
,
x
[
i
+
9
],
5
,
568446438
);
d
=
md5_gg
(
d
,
a
,
b
,
c
,
x
[
i
+
14
],
9
,
-
1019803690
);
c
=
md5_gg
(
c
,
d
,
a
,
b
,
x
[
i
+
3
],
14
,
-
187363961
);
b
=
md5_gg
(
b
,
c
,
d
,
a
,
x
[
i
+
8
],
20
,
1163531501
);
a
=
md5_gg
(
a
,
b
,
c
,
d
,
x
[
i
+
13
],
5
,
-
1444681467
);
d
=
md5_gg
(
d
,
a
,
b
,
c
,
x
[
i
+
2
],
9
,
-
51403784
);
c
=
md5_gg
(
c
,
d
,
a
,
b
,
x
[
i
+
7
],
14
,
1735328473
);
b
=
md5_gg
(
b
,
c
,
d
,
a
,
x
[
i
+
12
],
20
,
-
1926607734
);
a
=
md5_hh
(
a
,
b
,
c
,
d
,
x
[
i
+
5
],
4
,
-
378558
);
d
=
md5_hh
(
d
,
a
,
b
,
c
,
x
[
i
+
8
],
11
,
-
2022574463
);
c
=
md5_hh
(
c
,
d
,
a
,
b
,
x
[
i
+
11
],
16
,
1839030562
);
b
=
md5_hh
(
b
,
c
,
d
,
a
,
x
[
i
+
14
],
23
,
-
35309556
);
a
=
md5_hh
(
a
,
b
,
c
,
d
,
x
[
i
+
1
],
4
,
-
1530992060
);
d
=
md5_hh
(
d
,
a
,
b
,
c
,
x
[
i
+
4
],
11
,
1272893353
);
c
=
md5_hh
(
c
,
d
,
a
,
b
,
x
[
i
+
7
],
16
,
-
155497632
);
b
=
md5_hh
(
b
,
c
,
d
,
a
,
x
[
i
+
10
],
23
,
-
1094730640
);
a
=
md5_hh
(
a
,
b
,
c
,
d
,
x
[
i
+
13
],
4
,
681279174
);
d
=
md5_hh
(
d
,
a
,
b
,
c
,
x
[
i
+
0
],
11
,
-
358537222
);
c
=
md5_hh
(
c
,
d
,
a
,
b
,
x
[
i
+
3
],
16
,
-
722521979
);
b
=
md5_hh
(
b
,
c
,
d
,
a
,
x
[
i
+
6
],
23
,
76029189
);
a
=
md5_hh
(
a
,
b
,
c
,
d
,
x
[
i
+
9
],
4
,
-
640364487
);
d
=
md5_hh
(
d
,
a
,
b
,
c
,
x
[
i
+
12
],
11
,
-
421815835
);
c
=
md5_hh
(
c
,
d
,
a
,
b
,
x
[
i
+
15
],
16
,
530742520
);
b
=
md5_hh
(
b
,
c
,
d
,
a
,
x
[
i
+
2
],
23
,
-
995338651
);
a
=
md5_ii
(
a
,
b
,
c
,
d
,
x
[
i
+
0
],
6
,
-
198630844
);
d
=
md5_ii
(
d
,
a
,
b
,
c
,
x
[
i
+
7
],
10
,
1126891415
);
c
=
md5_ii
(
c
,
d
,
a
,
b
,
x
[
i
+
14
],
15
,
-
1416354905
);
b
=
md5_ii
(
b
,
c
,
d
,
a
,
x
[
i
+
5
],
21
,
-
57434055
);
a
=
md5_ii
(
a
,
b
,
c
,
d
,
x
[
i
+
12
],
6
,
1700485571
);
d
=
md5_ii
(
d
,
a
,
b
,
c
,
x
[
i
+
3
],
10
,
-
1894986606
);
c
=
md5_ii
(
c
,
d
,
a
,
b
,
x
[
i
+
10
],
15
,
-
1051523
);
b
=
md5_ii
(
b
,
c
,
d
,
a
,
x
[
i
+
1
],
21
,
-
2054922799
);
a
=
md5_ii
(
a
,
b
,
c
,
d
,
x
[
i
+
8
],
6
,
1873313359
);
d
=
md5_ii
(
d
,
a
,
b
,
c
,
x
[
i
+
15
],
10
,
-
30611744
);
c
=
md5_ii
(
c
,
d
,
a
,
b
,
x
[
i
+
6
],
15
,
-
1560198380
);
b
=
md5_ii
(
b
,
c
,
d
,
a
,
x
[
i
+
13
],
21
,
1309151649
);
a
=
md5_ii
(
a
,
b
,
c
,
d
,
x
[
i
+
4
],
6
,
-
145523070
);
d
=
md5_ii
(
d
,
a
,
b
,
c
,
x
[
i
+
11
],
10
,
-
1120210379
);
c
=
md5_ii
(
c
,
d
,
a
,
b
,
x
[
i
+
2
],
15
,
718787259
);
b
=
md5_ii
(
b
,
c
,
d
,
a
,
x
[
i
+
9
],
21
,
-
343485551
);
a
=
safe_add
(
a
,
olda
);
b
=
safe_add
(
b
,
oldb
);
c
=
safe_add
(
c
,
oldc
);
d
=
safe_add
(
d
,
oldd
);
}
return
Array
(
a
,
b
,
c
,
d
);
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function
md5_cmn
(
q
,
a
,
b
,
x
,
s
,
t
)
{
return
safe_add
(
bit_rol
(
safe_add
(
safe_add
(
a
,
q
),
safe_add
(
x
,
t
)),
s
),
b
);
}
function
md5_ff
(
a
,
b
,
c
,
d
,
x
,
s
,
t
)
{
return
md5_cmn
((
b
&
c
)
|
((
~
b
)
&
d
),
a
,
b
,
x
,
s
,
t
);
}
function
md5_gg
(
a
,
b
,
c
,
d
,
x
,
s
,
t
)
{
return
md5_cmn
((
b
&
d
)
|
(
c
&
(
~
d
)),
a
,
b
,
x
,
s
,
t
);
}
function
md5_hh
(
a
,
b
,
c
,
d
,
x
,
s
,
t
)
{
return
md5_cmn
(
b
^
c
^
d
,
a
,
b
,
x
,
s
,
t
);
}
function
md5_ii
(
a
,
b
,
c
,
d
,
x
,
s
,
t
)
{
return
md5_cmn
(
c
^
(
b
|
(
~
d
)),
a
,
b
,
x
,
s
,
t
);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function
safe_add
(
x
,
y
)
{
var
lsw
=
(
x
&
0xFFFF
)
+
(
y
&
0xFFFF
);
var
msw
=
(
x
>>
16
)
+
(
y
>>
16
)
+
(
lsw
>>
16
);
return
(
msw
<<
16
)
|
(
lsw
&
0xFFFF
);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function
bit_rol
(
num
,
cnt
)
{
return
(
num
<<
cnt
)
|
(
num
>>>
(
32
-
cnt
));
}
renderjs.js
View file @
720d75aa
...
@@ -552,6 +552,89 @@ var RenderJs = (function () {
...
@@ -552,6 +552,89 @@ var RenderJs = (function () {
};
};
}()),
}()),
GadgetCatalog
:
(
function
()
{
/*
* Gadget catalog provides API to get list of gadgets from a repository
*/
var
cache_id
=
"
setGadgetIndexUrlList
"
;
function
updateGadgetIndexFromURL
(
url
)
{
// split to base and document url
var
url_list
=
url
.
split
(
'
/
'
),
document_url
=
url_list
[
url_list
.
length
-
1
];
url_list
.
splice
(
$
.
inArray
(
document_url
,
url_list
),
1
);
var
base_url
=
url_list
.
join
(
'
/
'
),
web_dav
=
jIO
.
newJio
({
"
type
"
:
"
dav
"
,
"
username
"
:
""
,
"
password
"
:
""
,
"
url
"
:
base_url
});
web_dav
.
get
(
document_url
,
function
(
err
,
response
)
{
RenderJs
.
Cache
.
set
(
url
,
response
);
});
};
return
{
updateGadgetIndex
:
function
()
{
/*
* Update gadget index from all configured remote repositories.
*/
$
.
each
(
RenderJs
.
GadgetCatalog
.
getGadgetIndexUrlList
(),
function
(
index
,
value
)
{
updateGadgetIndexFromURL
(
value
);
});
},
setGadgetIndexUrlList
:
function
(
url_list
)
{
/*
* Set list of Gadget Index repositories.
*/
// store in Cache (html5 storage)
RenderJs
.
Cache
.
set
(
cache_id
,
url_list
)
},
getGadgetIndexUrlList
:
function
()
{
/*
* Get list of Gadget Index repositories.
*/
// get from Cache (html5 storage)
return
RenderJs
.
Cache
.
get
(
cache_id
,
undefined
)
},
getGadgetListThatProvide
:
function
(
service
)
{
/*
* Return list of all gadgets that providen a given service.
* Read this list from data structure created in HTML5 local
* storage by updateGadgetIndexFromURL
*/
// XXX: get from Cache stored index and itterate over it
// to find matching ones
var
gadget_list
=
new
Array
();
$
.
each
(
RenderJs
.
GadgetCatalog
.
getGadgetIndexUrlList
(),
function
(
index
,
url
)
{
// get repos from cache
var
cached_repo
=
RenderJs
.
Cache
.
get
(
url
);
$
.
each
(
cached_repo
[
'
gadget_list
'
],
function
(
index
,
gadget
)
{
if
(
jQuery
.
inArray
(
service
,
gadget
[
"
service_list
"
])
>
-
1
)
{
// gadget provides a service, add to list
gadget_list
.
push
(
gadget
);
}
}
)
});
return
gadget_list
;
},
registerServiceList
:
function
(
gadget
,
service_list
)
{
/*
* Register a service provided by a gadget.
*/
},
};
}()),
InteractionGadget
:
(
function
()
{
InteractionGadget
:
(
function
()
{
/*
/*
* Basic gadget interaction gadget implementation.
* Basic gadget interaction gadget implementation.
...
...
require-renderjs.js
View file @
720d75aa
...
@@ -3,11 +3,14 @@ require.config({
...
@@ -3,11 +3,14 @@ require.config({
paths
:
{
paths
:
{
jquery
:
"
lib/jquery/jquery
"
,
jquery
:
"
lib/jquery/jquery
"
,
"
jquery.json
"
:
"
lib/json/jquery.json.min
"
,
"
jquery.json
"
:
"
lib/json/jquery.json.min
"
,
"
davstorage
"
:
"
lib/jio/davstorage
"
,
"
md5
"
:
"
lib/jio/md5
"
,
"
jio
"
:
"
lib/jio/jio
"
,
renderjs
:
"
renderjs
"
renderjs
:
"
renderjs
"
},
},
shim
:
{
shim
:
{
"
jquery.json
"
:
[
"
jquery
"
],
"
jquery.json
"
:
[
"
jquery
"
],
renderjs
:
[
"
jquery
"
,
"
jquery.json
"
]
renderjs
:
[
"
jquery
"
,
"
jquery.json
"
,
"
md5
"
,
"
jio
"
,
"
davstorage
"
]
}
}
});
});
...
...
test/gadget_index/gadget_index.json
0 → 100644
View file @
720d75aa
{
"gadget_list"
:[
{
"title"
:
"HTML WYSIWYG"
,
"description"
:
"A simple HTML editor"
,
"url"
:
"http://example.com/html-editor.html"
,
"service_list"
:
[
"edit_html"
,
"view_html"
]},
{
"title"
:
"SVG WYSIWYG"
,
"description"
:
"A simple SVG editor"
,
"url"
:
"http://example.com/svg-editor.html"
,
"service_list"
:
[
"edit_svg"
,
"view_svg"
]}
]
}
\ No newline at end of file
test/renderjs_test.js
View file @
720d75aa
...
@@ -24,6 +24,14 @@ function parseJSONAndUpdateNameSpace(result) {
...
@@ -24,6 +24,14 @@ function parseJSONAndUpdateNameSpace(result) {
last_name
=
result
[
'
last_name
'
];
last_name
=
result
[
'
last_name
'
];
}
}
function
makeid
()
{
var
text
=
""
;
var
possible
=
"
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
"
;
for
(
var
i
=
0
;
i
<
5
;
i
++
)
text
+=
possible
.
charAt
(
Math
.
floor
(
Math
.
random
()
*
possible
.
length
));
return
text
;
}
function
setupRenderJSTest
(){
function
setupRenderJSTest
(){
/*
/*
* Main RenderJS test entry point
* Main RenderJS test entry point
...
@@ -164,5 +172,46 @@ function setupRenderJSTest(){
...
@@ -164,5 +172,46 @@ function setupRenderJSTest(){
});
});
});
});
module
(
"
GadgetCatalog
"
);
test
(
'
GadgetCatalog
'
,
function
()
{
cleanUp
();
// allow test to be run alone (i.e. url contains arguments)
var
base_url
=
window
.
location
.
protocol
+
"
//
"
+
window
.
location
.
hostname
+
window
.
location
.
pathname
;
// generate random argument to test always with new cache id
var
url_list
=
new
Array
(
base_url
+
'
/gadget_index/gadget_index.json?t=
'
+
makeid
());
RenderJs
.
GadgetCatalog
.
setGadgetIndexUrlList
(
url_list
)
deepEqual
(
url_list
,
RenderJs
.
GadgetCatalog
.
getGadgetIndexUrlList
());
RenderJs
.
GadgetCatalog
.
updateGadgetIndex
();
stop
();
// XXX: until we have a way to know that update which runs asynchronously is over
// we use hard coded timeouts.
setTimeout
(
function
(){
start
();
cached
=
RenderJs
.
Cache
.
get
(
url_list
[
0
]);
equal
(
"
HTML WYSIWYG
"
,
cached
[
"
gadget_list
"
][
0
][
"
title
"
]);
deepEqual
([
"
edit_html
"
,
"
view_html
"
],
cached
[
"
gadget_list
"
][
0
][
"
service_list
"
]);
// check that we can find gadgets that provide some service_list
gadget_list
=
RenderJs
.
GadgetCatalog
.
getGadgetListThatProvide
(
"
edit_html
"
);
equal
(
"
HTML WYSIWYG
"
,
gadget_list
[
0
][
"
title
"
]);
deepEqual
([
"
edit_html
"
,
"
view_html
"
],
gadget_list
[
0
][
"
service_list
"
]);
gadget_list
=
RenderJs
.
GadgetCatalog
.
getGadgetListThatProvide
(
"
view_html
"
);
equal
(
"
HTML WYSIWYG
"
,
gadget_list
[
0
][
"
title
"
]);
deepEqual
([
"
edit_html
"
,
"
view_html
"
],
gadget_list
[
0
][
"
service_list
"
]);
gadget_list
=
RenderJs
.
GadgetCatalog
.
getGadgetListThatProvide
(
"
edit_svg
"
);
equal
(
"
SVG WYSIWYG
"
,
gadget_list
[
0
][
"
title
"
]);
deepEqual
([
"
edit_svg
"
,
"
view_svg
"
],
gadget_list
[
0
][
"
service_list
"
]);
// no such service is provided by gadget repos
equal
(
0
,
RenderJs
.
GadgetCatalog
.
getGadgetListThatProvide
(
"
edit_html1
"
));
},
1000
)
});
};
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment