diff --git a/README.md b/README.md
index 414527f..e44df48 100644
--- a/README.md
+++ b/README.md
@@ -109,12 +109,10 @@ Once the index.html files have been built (one for each frontend) and a backend
The POG interface will allow also a very basic access to the DB data that may be useful to check that the application is actually writing something on the DB (even if you will not be able to make much sense out of the data you will see, as they are all encrypted!)
More information about building the PHP backend may be found in the `doc/install.php.txt` file.
- But if you have setup a $configuration['setup_password'] in target/php/configuration.php then a page with a textfield and a "Submit" link will appear.
- Just input your $configuration['setup_password'] value and click on "Submit" so [POG][pog] setup page will appear.
## Disclaimer
This application has not been fully tested, so there may be still problems due to the new build script or to the new repository structure. So, for the moment, **use it at your own risk!**
-[pog]: http://www.phpobjectgenerator.com/
+[pog]: http://www.phpobjectgenerator.com/
\ No newline at end of file
diff --git a/backend/checksum/properties/checksum.properties.json b/backend/checksum/properties/checksum.properties.json
index 1c2dae5..9a70ce7 100644
--- a/backend/checksum/properties/checksum.properties.json
+++ b/backend/checksum/properties/checksum.properties.json
@@ -1,4 +1,5 @@
{
- "request.path": "json",
+ "request.path": "../json",
+ "dump.path": "/../dump",
"should.pay.toll": "true"
}
\ No newline at end of file
diff --git a/backend/dev/properties/dev.properties.json b/backend/dev/properties/dev.properties.json
index 1c2dae5..9a70ce7 100644
--- a/backend/dev/properties/dev.properties.json
+++ b/backend/dev/properties/dev.properties.json
@@ -1,4 +1,5 @@
{
- "request.path": "json",
+ "request.path": "../json",
+ "dump.path": "/../dump",
"should.pay.toll": "true"
}
\ No newline at end of file
diff --git a/backend/php/properties/php.properties.json b/backend/php/properties/php.properties.json
index 09196c9..8c2ff05 100644
--- a/backend/php/properties/php.properties.json
+++ b/backend/php/properties/php.properties.json
@@ -1,4 +1,5 @@
{
- "request.path": "index.php",
+ "request.path": "../index.php",
+ "dump.path": "/../dump.php",
"should.pay.toll": "false"
}
diff --git a/backend/python/properties/python.properties.json b/backend/python/properties/python.properties.json
index 322f174..b98364e 100644
--- a/backend/python/properties/python.properties.json
+++ b/backend/python/properties/python.properties.json
@@ -1,4 +1,5 @@
{
- "request.path": "clipperz.py",
+ "request.path": "../clipperz.py",
+ "dump.path": "/../clipperz.py",
"should.pay.toll": "false"
}
diff --git a/frontend/beta/html/index_template.html b/frontend/beta/html/index_template.html
index c3fd727..25f6a87 100644
--- a/frontend/beta/html/index_template.html
+++ b/frontend/beta/html/index_template.html
@@ -15,7 +15,7 @@
@js_EMBEDDED@
Have a better and safer Clipperz experience with Firefox. However Clipperz works just fine also with Opera, Safari and MS Internet Explorer!
",
+
+// Login with OTP - message panel
+'OTPloginMessagePanelInitialTitle': "Logging in using a one-time passphrase",
+'OTPloginMessagePanelInitialText': "Sending OTP credentials …",
+'OTPloginMessagePanelLoadingTitle': "Logging in using a one-time passphrase",
+'OTPloginMessagePanelLoadingText': "Fetching encrypted authentication data from the server …",
+'OTPloginMessagePanelProcessingTitle': "Logging in using a one-time passphrase",
+'OTPloginMessagePanelProcessingText': "Local decryption of authentication data",
+
+// Regular login - message panel
+'loginMessagePanelInitialTitle': "Logging in …",
+'loginMessagePanelInitialText': "---",
+'loginMessagePanelInitialButtonLabel': "Cancel",
+'loginMessagePanelConnectedTitle': "Connected",
+'loginMessagePanelConnectedText': "Done",
+'loginMessagePanelFailureTitle': "Error",
+'loginMessagePanelFailureText': "Login failed",
+'loginMessagePanelFailureButtonLabel': "Close",
+
+// Regular login - message panel - connection
+'connectionLoginSendingCredentialsMessageTitle': "Verifying credentials",
+'connectionLoginSendingCredentialsMessageText': "Sending credentials",
+'connectionLoginCredentialsVerificationMessageTitle': "Verifying credentials",
+'connectionLoginCredentialsVerificationMessageText': "Performing SRP authentication",
+'connectionLoginDoneMessageTitle': "Verifying credentials",
+'connectionLoginDoneMessageText': "Connected",
+
+// Regular login - message panel - user
+'userLoginPanelUpgradingUserCredentialsMessageTitle': "Verifying credentials",
+'userLoginPanelUpgradingUserCredentialsMessageText': "Upgrading your credentials to a new authentication schema",
+'userLoginPanelConnectedMessageTitle': "User authenticated",
+'userLoginPanelConnectedMessageText': "Successfully logged in",
+'userLoginPanelTryingAnOlderConnectionSchemaMessageTitle': "Verifying credentials",
+'userLoginPanelTryingAnOlderConnectionSchemaMessageText': "Trying an older authentication schema",
+'userLoginPanelLoadingUserDataMessageTitle': "User authenticated",
+'userLoginPanelLoadingUserDataMessageText': "Downloading encrypted card headers from Clipperz",
+'userLoginPanelDecryptingUserDataMessageTitle': "User authenticated",
+'userLoginPanelDecryptingUserDataMessageText': "Local decryption of card headers",
+'userLoginPanelDecryptingUserStatisticsMessageTitle': "User authenticated",
+'userLoginPanelDecryptingUserStatisticsMessageText': "Local decryption of usage statistics",
+
+// Registration page - splash alert
+'splashAlertTitle': "Welcome to Clipperz!",
+'splashAlertText': "\
+ \
+
Some security advice
\
+
\
+
Storing your data at Clipperz is as secure as the passphrase you choose to protect them. Nobody can access them unless they know your passphrase.
\
+
If you are going to use Clipperz for safeguarding sensitive and critical information please make sure to use a strong passphrase. The longer the better!
\
+
Clipperz will not be able to recover a lost passphrase!
\
+
\
+
For any further information, please refer to Clipperz website.
",
+'splashAlertCloseButtonLabel': "Ok",
+
+// Registration page - form
+'registrationFormTitle': "create your account",
+'registrationFormUsernameLabel': "username",
+'registrationFormPassphraseLabel': "passphrase",
+'registrationFormRetypePassphraseLabel': "re-enter passphrase",
+'registrationFormSafetyCheckLabel': "I understand that Clipperz will not be able to recover a lost passphrase.",
+'registrationFormTermsOfServiceCheckLabel': "I have read and agreed to the Terms of Service.",
+'registrationFormDoYouAlreadyHaveAnAccountLabel': "do you already have an account?",
+'registrationFormSimplyLoginLabel': "simply login",
+'registrationFormButtonLabel': "Register",
+
+// Registration page - warning messages
+'registrationFormWarningMessageNotMatchingPassphrases': "Your passphrases don't match, please re-type them.",
+'registrationFormWarningMessageSafetyCheckNotSelected': "Please read and check all the boxes below.",
+'registrationFormWarningMessageTermsOfServiceCheckNotSelected': "You need to agree to the Terms of Service.",
+
+// Registration page - message panel
+'registrationMessagePanelInitialTitle': "Creating account …",
+'registrationMessagePanelInitialText': "---",
+'registrationMessagePanelInitialButtonLabel': "Cancel",
+'registrationMessagePanelRegistrationDoneTitle': "Registration",
+'registrationMessagePanelRegistrationDoneText': "Done",
+'registrationMessagePanelFailureTitle': "Registration failed",
+'registrationMessagePanelFailureButtonLabel': "Close",
+
+// Registration page - message panel - connection
+'connectionRegistrationSendingRequestMessageText': "Verifying credentials",
+'connectionRegistrationSendingCredentialsMessageText': "Sending credentials",
+
+// Registration page - splash panel
+'registrationSplashPanelTitle': "Security advice",
+'registrationSplashPanelDescription': "
These are your Clipperz credentials, take good care of them. Clipperz will never display your username and passphrase a second time!
To unlock your account, please enter your passphrase.
",
+'unlockButtonLabel': "Unlock",
+
+// Account panel - change passphrase
+'changePasswordTabLabel': "Change your passphrase",
+'changePasswordTabTitle': "Change your passphrase",
+
+'changePasswordFormUsernameLabel': "username",
+'changePasswordFormOldPassphraseLabel': "old passphrase",
+'changePasswordFormNewPassphraseLabel': "new passphrase",
+'changePasswordFormRetypePassphraseLabel': "re-enter new passphrase",
+'changePasswordFormSafetyCheckboxLabel': "I understand that Clipperz will not be able to recover a lost passphrase.",
+'changePasswordFormSubmitLabel': "Change passphrase",
+
+// Account panel - change passphrase - warning messages
+'changePasswordFormWrongUsernameWarning': "Wrong username",
+'changePasswordFormWrongPassphraseWarning': "Wrong passphrase",
+'changePasswordFormWrongRetypePassphraseWarning': "Your passphrases don't match, please re-type them.",
+'changePasswordFormSafetyCheckWarning': "Please read and check the box below.",
+
+// Account panel - change passphrase - progress dialog
+'changePasswordFormProgressDialogTitle': "Changing user credentials",
+'changePasswordFormProgressDialogEmptyText': "---",
+'changePasswordFormProgressDialogConnectedMessageTitle': "Connected",
+'changePasswordFormProgressDialogConnectedMessageText': "Done",
+'changePasswordFormProgressDialogErrorMessageTitle': "Error",
+'changePasswordFormProgressDialogErrorMessageText': "Credentials change failed!",
+
+'changeCredentialsPanelEncryptingDataMessageTitle': "Changing your passphrase",
+'changeCredentialsPanelEncryptingDataMessageText': "Local encryption of card headers",
+'changeCredentialsPanelCreatingNewCredentialsMessageTitle': "Changing your passphrase",
+'changeCredentialsPanelCreatingNewCredentialsMessageText': "Updating your credentials",
+'changeCredentialsPanelSendingNewCredentialsToTheServerMessageTitle': "Changing your passphrase",
+'changeCredentialsPanelSendingNewCredentialsToTheServerMessageText': "Uploading your encrypted credentials to Clipperz",
+'changeCredentialsPanelDoneMessageTitle': "Changing your passphrase",
+'changeCredentialsPanelDoneMessageText': "Done",
+
+// Account panel - OTP
+'manageOTPTabLabel': "Manage your one-time passphrases",
+'manageOTPTabTitle': "Manage your one-time passphrases",
+
+'manageOTPTabDescription': "\
+
A one-time passphrase works like your regular passphrase, but can be used only once.
\
+
If the same passphrase is used again at a later stage in a login attempt it will be rejected and the login process will fail.
\
+
Immediately after a successful login, your one-time passphrase will be deleted preventing any fraudulent access.
\
+
One-time passphrases are an excellent choice if one is concerned about keyloggers or spyware infections that may be collecting data from compromised machines.
\
+
It's strongly advisable to use one-time passphrases when accessing Clipperz from public terminals, such as Internet cafes and libraries.
The login history is not available while using the offline version of Clipperz.
",
+
+'loginHistoryLoadingMessage': "\
+
Loading data
\
+
Please wait …
",
+
+'loginHistoryLoadedMessage': "\
+
Your latest 10 logins
\
+ ",
+
+'loginHistoryIPLabel': "IP",
+'loginHistoryTimeLabel': "date",
+'loginHistoryCurrentSessionText': "current session",
+'loginHistoryReloadButtonLabel': "Reload login history",
+
+// Account panel - delete account
+'deleteAccountTabLabel': "Delete your account",
+'deleteAccountTabTitle': "Delete your account",
+
+'deleteAccountFormUsernameLabel': "username",
+'deleteAccountFormPassphraseLabel': "passphrase",
+'deleteAccountFormSafetyCheckboxLabel': "I understand that all my data will be deleted and that this action is irreversible.",
+'deleteAccountFormSubmitLabel': "Delete my account",
+
+//Account panel - delete account - warnings
+'deleteAccountFormWrongUsernameWarning': "Wrong username",
+'deleteAccountFormWrongPassphraseWarning': "Wrong passphrase",
+'deleteAccountFormSafetyCheckWarning': "Please read and check the box below.",
+
+//Account panel - delete account - confirmation
+'accountPanelDeletingAccountPanelConfirmationTitle': "ATTENTION",
+'accountPanelDeleteAccountPanelConfirmationText': "Are your sure you want to delete your account?",
+'accountPanelDeleteAccountPanelConfirmButtonLabel': "Yes",
+'accountPanelDeleteAccountPanelDenyButtonLabel': "No",
+
+//Account panel - delete account - confirmation
+'accountPanelDeletingAccountPanelProgressTitle': "Deleting the account data",
+'accountPanelDeletingAccountPanelProgressText': "The operation could take long, please be patient.",
+
+//Data panel - offline copy
+'offlineCopyTabLabel': "Offline copy",
+'offlineCopyTabTitle': "Offline copy",
+
+'offlineCopyTabDescription': "\
+ \
+
With just one click you can dump all your encrypted data from Clipperz servers to your hard disk and create a read-only offline version of Clipperz to be used when you are not connected to the Internet.
\
+
The read-only version is as secure as the read-and-write one and will not expose your data to higher risks since they both share the same code and security architecture.
\
+ \
+
Click the link below to start the download.
\
+
The browser will ask you what to do with the “Clipperz_YYYYMMDD.html” file. Save it on your hard disk.
\
+
Double click on the downloaded file to launch the offline version in your browser.
Quite often a confidential piece of information needs to be shared with one or more persons.
\
+
This could be as simple as giving your colleague the access code of your voice mailbox when you are out of the office, or as complicated as enabling the entitled heirs to access your safe deposit box at the local bank when you pass on.
\
+
Clipperz can make sharing your secrets a secure and straightforward process.
JSON enables a “lossless” export of your cards. All the information will be preserved, including direct login configurations.
\
+
This custom format it’s quite convenient if you need to move some of all of your cards to a different Clipperz account. Or if you want to restore a card that has been accidentally deleted.
\
+
Click on the link below to start the export process.
",
+
+'exportLinkLabel': "Export to JSON",
+
+'exportDataInProgressDescription': "
Exporting, please wait while your data are being processed …
",
+
+'exportDataDescription': "\
+
Instructions
\
+
Copy the text below to your favorite editor and save it. (e.g. “clipperz_export_20071217.json”)
A bookmarklet is a simple “one-click” tool that can perform very useful tasks. It can be saved and used like a normal web page bookmark.
\
+
The Clipperz bookmarklet will help you to quickly create new cards and new “direct logins” within existing cards.
\
+
Please note that the bookmarklet does not include any information related to your account (e.g. your username or passphrase), the bookmarklet is a general tool containing the same code for every Clipperz user.
\
+
How to install the bookmarklet
\
+ Firefox, Camino, Opera, Safari\
+ \
+
Make sure that the “Bookmarks Bar” is displayed by selecting “View > Toolbars > Bookmarks”, or similar menu items, from the browser menu.
\
+
Drag and drop the “Add to Clipperz” link below to the bookmark bar.
\
+ \
+ \
+
Internet Explorer
\
+ \
+
Make sure that the “Links” toolbar is displayed by selecting “View > Toolbars > Links” from the browser menu.
\
+
Right-click on the “Add to Clipperz” link below.
\
+
Select “Add to favorites” from the contextual menu.
\
+
Click “Yes” for any security message that pops up.
HTTP authentication is a method designed to allow a web browser to provide credentials – in the form of a username and password – including them in a website address (HTTP or HTTPS URL).
\
+
Nowadays it is rarely used, but it can still be found on small, private websites. You can tell that a website is protected by HTTP authentication when the browser displays a pop-up window to enter username and password.
\
+
Unfortunately the Clipperz bookmarklet does not work on websites that use HTTP authentication. However you can still create a “direct login”.
\
+ \
+
How to create a “direct login” for a website that uses HTTP authentication
\
+ \
+
Store website URL, username and password in a new card.
\
+
Copy the configuration below and paste it to the large text area in the “Direct logins” section of the new card.
\
+
Press the Add direct login button, bind URL, username and password fields and then click Save.
No matter which kind of confidential data you need to protect, create a custom card to match your needs.
",
+ 'fields': [
+ {label:"Label 1", type:'TXT'},
+ {label:"Label 2", type:'TXT'},
+ {label:"Label 3", type:'TXT'}
+ ]
+ }
+},
+
+
+'recordFieldTypologies': {
+ 'TXT': {
+ description: "simple text field",
+ shortDescription: "text"
+ },
+ 'PWD': {
+ description: "simple text field, with default status set to hidden",
+ shortDescription: "password"
+ },
+ 'URL': {
+ description: "simple text field in edit mode, that became an active url in view mode",
+ shortDescription: "web address"
+ },
+ 'DATE': {
+ description: "a value set with a calendar helper",
+ shortDescription: "date"
+ },
+ 'ADDR': {
+ description: "just like the URL, but the active link points to Google Maps (or similar service) passing the address value as argument",
+ shortDescription: "street address"
+ },
+ 'CHECK': {
+ description: "check description",
+ shortDescription: "check"
+ },
+ 'RADIO': {
+ description: "radio description",
+ shortDescription: "radio"
+ },
+ 'SELECT': {
+ description: "select description",
+ shortDescription: "select"
+ }
+},
+
+// Cards block - new card - warnings
+'newRecordPanelGeneralExceptionTitle': "Error",
+'newRecordPanelGeneralExceptionMessage': "The configuration text is not valid. Make sure to get your text from the bookmarklet pop-up and retry.",
+'newRecordPanelWrongBookmarkletVersionExceptionTitle': "Error",
+'newRecordPanelWrongBookmarkletVersionExceptionMessage': "The configuration text has been generated by an old version of the bookmarklet. Please update your bookmarklet and retry.",
+'newRecordPanelExceptionPanelCloseButtonLabel': "Cancel",
+
+// Cards block - delete card
+'mainPanelDeletingRecordPanelConfirmationTitle': "Deleting selected card",
+'mainPanelDeleteRecordPanelConfirmationText': "Do your really want to delete the selected card?",
+'mainPanelDeleteRecordPanelConfirmButtonLabel': "Yes",
+'mainPanelDeleteRecordPanelDenyButtonLabel': "No",
+'mainPanelDeletingRecordPanelInitialTitle': "Deleting selected card",
+'mainPanelDeletingRecordPanelInitialText': "---",
+'mainPanelDeletingRecordPanelCompletedText': "Done",
+
+// Cards block - delete card panel
+'deleteRecordPanelCollectRecordDataMessageTitle': "Delete card",
+'deleteRecordPanelCollectRecordDataMessageText': "Updating card list",
+'deleteRecordPanelEncryptUserDataMessageTitle': "Delete card",
+'deleteRecordPanelEncryptUserDataMessageText': "Local encryption of card headers",
+'deleteRecordPanelSendingDataToTheServerMessageTitle': "Delete card",
+'deleteRecordPanelSendingDataToTheServerMessageText': "Uploading encrypted card headers to Clipperz",
+'deleteRecordPanelUpdatingTheInterfaceMessageTitle': "Delete card",
+'deleteRecordPanelUpdatingTheInterfaceMessageText': "Updating the interface",
+
+// Cards block - no record selected
+'recordDetailNoRecordSelectedTitle': "No card selected",
+'recordDetailNoRecordSelectedDescription': "
Please select a card from the list on the left.
",
+
+// Cards block - loading messages
+'recordDetailLoadingRecordMessage': "Downloading encrypted card from Clipperz",
+'recordDetailDecryptingRecordMessage': "Local decryption of card\'s data",
+'recordDetailLoadingRecordVersionMessage': "Downloading latest card version",
+'recordDetailDecryptingRecordVersionMessage': "Local decryption of latest version",
+'recordDetailLoadingErrorMessageTitle': "Error while downloading the card",
+
+// Cards block - card details
+'recordDetailNotesLabel': "Notes",
+'recordDetailLabelFieldColumnLabel': "Field label",
+'recordDetailDataFieldColumnLabel': "Field data",
+'recordDetailTypeFieldColumnLabel': "Type",
+
+'recordDetailSavingChangesMessagePanelInitialTitle': "Saving card",
+'recordDetailSavingChangesMessagePanelInitialText': "---",
+
+'recordDetailRemoveFieldButtonLabel': "-",
+'recordDetailAddFieldButtonLabel': "Add new field",
+'recordDetailPasswordFieldHelpLabel': "click the stars to select the password and then Ctrl-C to copy",
+
+'recordDetailPasswordFieldScrambleLabel': "scramble",
+'recordDetailPasswordFieldUnscrambleLabel': "unscramble",
+
+'recordDetailDirectLoginBlockTitle': "Direct logins",
+'recordDetailNewDirectLoginDescription': "
';
+ nodes = tempTableEl.firstChild.firstChild.firstChild.childNodes;
+ }
+ if (where == 'beforebegin') {
+ nodes.reverse();
+// el.parentNode.insertBefore(node, el);
+ MochiKit.Base.map(function(aNode) {el.parentNode.insertBefore(aNode, el)}, nodes);
+ } else if (where == 'afterbegin') {
+ nodes.reverse();
+// el.insertBefore(node, el.firstChild);
+ MochiKit.Base.map(function(aNode) {el.insertBefore(aNode, el.firstChild)}, nodes);
+ } else if (where == 'beforeend') {
+// el.appendChild(node);
+ MochiKit.Base.map(function(aNode) {el.appendChild(aNode)}, nodes);
+ } else if (where == 'afterend') {
+// el.parentNode.insertBefore(node, el.nextSibling);
+ MochiKit.Base.map(function(aNode) {el.parentNode.insertBefore(aNode, el.nextSibling)}, nodes);
+ }
+
+ return nodes;
+ }
+
+ /**
+ * Inserts an HTML fragment into the Dom
+ * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
+ * @param {HTMLElement} el The context element
+ * @param {String} html The HTML fragmenet
+ * @return {HTMLElement} The new node
+ */
+ this.insertHtml = function(where, el, html){
+ where = where.toLowerCase();
+// if(el.insertAdjacentHTML){
+ if(Clipperz_IEisBroken){
+ var tag = el.tagName.toLowerCase();
+ if(tag == 'table' || tag == 'tbody' || tag == 'tr'){
+ return insertIntoTable(tag, where, el, html);
+ }
+ switch(where){
+ case 'beforebegin':
+ el.insertAdjacentHTML(where, html);
+ return el.previousSibling;
+ case 'afterbegin':
+ el.insertAdjacentHTML(where, html);
+ return el.firstChild;
+ case 'beforeend':
+ el.insertAdjacentHTML(where, html);
+ return el.lastChild;
+ case 'afterend':
+ el.insertAdjacentHTML(where, html);
+ return el.nextSibling;
+ }
+ throw 'Illegal insertion point -> "' + where + '"';
+ }
+ var range = el.ownerDocument.createRange();
+ var frag;
+ switch(where){
+ case 'beforebegin':
+ range.setStartBefore(el);
+ frag = range.createContextualFragment(html);
+ el.parentNode.insertBefore(frag, el);
+ return el.previousSibling;
+ case 'afterbegin':
+ if(el.firstChild){ // faster
+ range.setStartBefore(el.firstChild);
+ }else{
+ range.selectNodeContents(el);
+ range.collapse(true);
+ }
+ frag = range.createContextualFragment(html);
+ el.insertBefore(frag, el.firstChild);
+ return el.firstChild;
+ case 'beforeend':
+ if(el.lastChild){
+ range.setStartAfter(el.lastChild); // faster
+ }else{
+ range.selectNodeContents(el);
+ range.collapse(false);
+ }
+ frag = range.createContextualFragment(html);
+ el.appendChild(frag);
+ return el.lastChild;
+ case 'afterend':
+ range.setStartAfter(el);
+ frag = range.createContextualFragment(html);
+ el.parentNode.insertBefore(frag, el.nextSibling);
+ return el.nextSibling;
+ }
+ throw 'Illegal insertion point -> "' + where + '"';
+ };
+
+ /**
+ * Creates new Dom element(s) and inserts them before el
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} o The Dom object spec (and children)
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ this.insertBefore = function(el, o, returnElement){
+ el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
+ var newNode;
+ if(this.useDom){
+ newNode = createDom(o, null);
+ el.parentNode.insertBefore(newNode, el);
+ }else{
+ var html = createHtml(o);
+ newNode = this.insertHtml('beforeBegin', el, html);
+ }
+ return returnElement ? YAHOO.Element.get(newNode, true) : newNode;
+ };
+
+ /**
+ * Creates new Dom element(s) and inserts them after el
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} o The Dom object spec (and children)
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ this.insertAfter = function(el, o, returnElement){
+ el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
+ var newNode;
+ if(this.useDom){
+ newNode = createDom(o, null);
+ el.parentNode.insertBefore(newNode, el.nextSibling);
+ }else{
+ var html = createHtml(o);
+ newNode = this.insertHtml('afterEnd', el, html);
+ }
+ return returnElement ? YAHOO.Element.get(newNode, true) : newNode;
+ };
+
+ /**
+ * Creates new Dom element(s) and appends them to el
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} o The Dom object spec (and children)
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ this.append = function(el, o, returnElement){
+ el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
+ var newNode;
+ if(this.useDom){
+ newNode = createDom(o, null);
+ el.appendChild(newNode);
+ }else{
+ var html = createHtml(o);
+ newNode = this.insertHtml('beforeEnd', el, html);
+ }
+ return returnElement ? YAHOO.Element.get(newNode, true) : newNode;
+ };
+
+ /**
+ * Creates new Dom element(s) and overwrites the contents of el with them
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} o The Dom object spec (and children)
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ this.overwrite = function(el, o, returnElement){
+ el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
+ el.innerHTML = createHtml(o);
+ return returnElement ? YAHOO.Element.get(el.firstChild, true) : el.firstChild;
+ };
+
+ /**
+ * Creates a new Clipperz.YUI.DomHelper.Template from the Dom object spec
+ * @param {Object} o The Dom object spec (and children)
+ * @return {Clipperz.YUI.DomHelper.Template} The new template
+ */
+ this.createTemplate = function(o){
+ var html = createHtml(o);
+ return new Clipperz.YUI.DomHelper.Template(html);
+ };
+}();
+
+/**
+* @class Clipperz.YUI.DomHelper.Template
+* Represents an HTML fragment template.
+* For more information see this blog post with examples.
+*
+* This class is also available as Clipperz.YUI.Template.
+* @constructor
+* @param {String/Array} html The HTML fragment or an array of fragments to join('') or multiple arguments to join('')
+*/
+Clipperz.YUI.DomHelper.Template = function(html){
+ if(html instanceof Array){
+ html = html.join('');
+ }else if(arguments.length > 1){
+ html = Array.prototype.join.call(arguments, '');
+ }
+ /**@private*/
+ this.html = html;
+};
+Clipperz.YUI.DomHelper.Template.prototype = {
+ /**
+ * Returns an HTML fragment of this template with the specified values applied
+ * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+ * @return {String}
+ */
+ applyTemplate : function(values){
+ if(this.compiled){
+ return this.compiled(values);
+ }
+ var empty = '';
+ var fn = function(match, index){
+ if(typeof values[index] != 'undefined'){
+ return values[index];
+ }else{
+ return empty;
+ }
+ }
+ return this.html.replace(this.re, fn);
+ },
+
+ /**
+ * The regular expression used to match template variables
+ * @type RegExp
+ * @property
+ */
+ re : /\{([\w|-]+)\}/g,
+
+ /**
+ * Compiles the template into an internal function, eliminating the RegEx overhead
+ */
+ compile : function(){
+ var body = ["this.compiled = function(values){ return ['"];
+ body.push(this.html.replace(this.re, "', values['$1'], '"));
+ body.push("'].join('');};");
+ eval(body.join(''));
+ return this;
+ },
+
+ /**
+ * Applies the supplied values to the template and inserts the new node(s) before el
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ insertBefore: function(el, values, returnElement){
+ el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
+ var newNode = Clipperz.YUI.DomHelper.insertHtml('beforeBegin', el, this.applyTemplate(values));
+ return returnElement ? YAHOO.Element.get(newNode, true) : newNode;
+ },
+
+ /**
+ * Applies the supplied values to the template and inserts the new node(s) after el
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ insertAfter : function(el, values, returnElement){
+ el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
+ var newNode = Clipperz.YUI.DomHelper.insertHtml('afterEnd', el, this.applyTemplate(values));
+ return returnElement ? YAHOO.Element.get(newNode, true) : newNode;
+ },
+
+ /**
+ * Applies the supplied values to the template and append the new node(s) to el
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ append : function(el, values, returnElement){
+ var sanitizedValues;
+ var key;
+
+ sanitizedValues = {};
+ for (key in values) {
+ sanitizedValues[key] = Clipperz.Base.sanitizeString(values[key]);
+ }
+ el = (typeof el == 'string') ? YAHOO.util.Dom.get(el) : el;
+ var newNode = Clipperz.YUI.DomHelper.insertHtml('beforeEnd', el, this.applyTemplate(sanitizedValues));
+
+ return newNode;
+ },
+
+ /**
+ * Applies the supplied values to the template and overwrites the content of el with the new node(s)
+ * @param {String/HTMLElement/Element} el The context element
+ * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
+ * @param {Boolean} returnElement (optional) true to return a YAHOO.Element
+ * @return {HTMLElement} The new node
+ */
+ overwrite : function(el, values, returnElement){
+ el = el.dom ? el.dom : YAHOO.util.Dom.get(el);
+ el.innerHTML = '';
+ var newNode = Clipperz.YUI.DomHelper.insertHtml('beforeEnd', el, this.applyTemplate(values));
+ return returnElement ? YAHOO.Element.get(newNode, true) : newNode;
+ }
+};
+/**
+ * Alias for applyTemplate
+ * @method
+ */
+Clipperz.YUI.DomHelper.Template.prototype.apply = Clipperz.YUI.DomHelper.Template.prototype.applyTemplate;
+
+Clipperz.YUI.Template = Clipperz.YUI.DomHelper.Template;
diff --git a/frontend/delta/js/Clipperz/YUI/DomQuery.js b/frontend/delta/js/Clipperz/YUI/DomQuery.js
new file mode 100644
index 0000000..c1af0ca
--- /dev/null
+++ b/frontend/delta/js/Clipperz/YUI/DomQuery.js
@@ -0,0 +1,709 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
+if (typeof(Clipperz.YUI) == 'undefined') { Clipperz.YUI = {}; }
+
+
+/*
+ * yui-ext 0.40
+ * Copyright(c) 2006, Jack Slocum.
+ */
+
+/**
+ * @class Clipperz.YUI.DomQuery
+ * Provides high performance selector/xpath processing by compiling queries into reusable functions.
+ * New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
+ * @singleton
+ */
+Clipperz.YUI.DomQuery = function(){
+ var cache = {}, simpleCache = {}, valueCache = {};
+ var nonSpace = /\S/;
+ var trimRe = /^\s*(.*?)\s*$/;
+ var tplRe = /\{(\d+)\}/g;
+ var modeRe = /^(\s?[\/>]\s?|\s|$)/;
+ var clsRes = {};
+
+ function child(p, index){
+ var i = 0;
+ var n = p.firstChild;
+ while(n){
+ if(n.nodeType == 1){
+ i++;
+ if(i == index){
+ return n;
+ }
+ }
+ n = n.nextSibling;
+ }
+ return null;
+ };
+
+ function next(d){
+ var n = d.nextSibling;
+ while(n && n.nodeType != 1){
+ n = n.nextSibling;
+ }
+ return n;
+ };
+
+ function prev(d){
+ var n = d.previousSibling;
+ while(n && n.nodeType != 1){
+ n = n.previousSibling;
+ }
+ return n;
+ };
+
+ function clean(d){
+ var n = d.firstChild, ni = -1;
+ while(n){
+ var nx = n.nextSibling;
+ if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
+ d.removeChild(n);
+ }else{
+ n.nodeIndex = ++ni;
+ }
+ n = nx;
+ }
+ return this;
+ };
+
+ function byClassName(c, a, v){
+ if(!v){
+ return c;
+ }
+ var re = clsRes[v];
+ if(!re){
+ re = new RegExp('(?:^|\\s)(?:' + v + ')(?:\\s|$)');
+ clsRes[v] = re;
+ }
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ if(re.test(ci.className)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ };
+
+ function convert(c){
+ if(c.slice){
+ return c;
+ }
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ r[r.length] = c[i];
+ }
+ return r;
+ };
+
+ function attrValue(n, attr){
+ if(!n.tagName && typeof n.length != 'undefined'){
+ n = n[0];
+ }
+ if(!n){
+ return null;
+ }
+ if(attr == 'for'){
+ return n.htmlFor;
+ }
+ if(attr == 'class' || attr == 'className'){
+ return n.className;
+ }
+ return n.getAttribute(attr) || n[attr];
+
+ };
+
+ function getNodes(ns, mode, tagName){
+ var result = [], cs;
+ if(!ns){
+ return result;
+ }
+ mode = mode ? mode.replace(trimRe, '$1') : '';
+ tagName = tagName || '*';
+ if(ns.tagName || ns == document){
+ ns = [ns];
+ }
+ if(mode != '/' && mode != '>'){
+ for(var i = 0, ni; ni = ns[i]; i++){
+ cs = ni.getElementsByTagName(tagName);
+ result = concat(result, cs);
+ }
+ }else{
+ for(var i = 0, ni; ni = ns[i]; i++){
+ var cn = ni.getElementsByTagName(tagName);
+ for(var j = 0, cj; cj = cn[j]; j++){
+ if(cj.parentNode == ni){
+ result[result.length] = cj;
+ }
+ }
+ }
+
+ }
+ return result;
+ };
+
+ function concat(a, b){
+ if(b.slice){
+ return a.concat(b);
+ }
+ for(var i = 0, l = b.length; i < l; i++){
+ a[a.length] = b[i];
+ }
+ return a;
+ }
+
+ function byTag(cs, tagName){
+ if(cs.tagName || cs == document){
+ cs = [cs];
+ }
+ if(!tagName){
+ return cs;
+ }
+ var r = []; tagName = tagName.toLowerCase();
+ for(var i = 0, ci; ci = cs[i]; i++){
+ if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ };
+
+ function byId(cs, attr, id){
+ if(cs.tagName || cs == document){
+ cs = [cs];
+ }
+ if(!id){
+ return cs;
+ }
+ var r = [];
+ for(var i = 0, l = cs.length; i < l; i++){
+ var ci = cs[i];
+ if(ci && ci.id == id){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ };
+
+ function byAttribute(cs, attr, value, op, custom){
+ var r = [], st = custom=='{';
+ var f = Clipperz.YUI.DomQuery.operators[op];
+ for(var i = 0, l = cs.length; i < l; i++){
+ var a;
+ if(st){
+ a = Clipperz.YUI.DomQuery.getStyle(cs[i], attr);
+ }
+ else if(attr == 'class' || attr == 'className'){
+ a = cs[i].className;
+ }else if(attr == 'for'){
+ a = cs[i].htmlFor;
+ }else{
+ a = cs[i].getAttribute(attr);
+ }
+ if((f && f(a, value)) || (!f && a)){
+ r[r.length] = cs[i];
+ }
+ }
+ return r;
+ };
+
+ function byPseudo(cs, name, value){
+ return Clipperz.YUI.DomQuery.pseudos[name](cs, value);
+ };
+
+ // This is for IE MSXML which does not support expandos.
+ // IE runs the same speed using setAttribute, however FF slows way down
+ // and Safari completely fails so they need to continue to use expandos.
+ // Branched at load time for faster execution.
+ var isIE = window.ActiveXObject;
+ var addAttr = isIE ?
+ function(n, a, v){
+ n.setAttribute(a, v);
+ } :
+ function(n, a, v){
+ n[a] = v;
+ };
+ var getAttr = isIE ?
+ function(n, a){
+ return n.getAttribute(a);
+ } :
+ function(n, a){
+ return n[a];
+ };
+ var clearAttr = isIE ?
+ function(n, a){
+ n.removeAttribute(a);
+ } :
+ function(n, a, v){
+ delete n[a];
+ };
+
+ function nodup(cs){
+ if(!cs.length){
+ return cs;
+ }
+ addAttr(cs[0], '_nodup', true);
+ var r = [cs[0]];
+ for(var i = 1, len = cs.length; i < len; i++){
+ var c = cs[i];
+ if(!getAttr(c, '_nodup')){
+ addAttr(c, '_nodup', true);
+ r[r.length] = c;
+ }
+ }
+ for(var i = 0, len = cs.length; i < len; i++){
+ clearAttr(cs[i], '_nodup');
+ }
+ return r;
+ }
+
+ function quickDiff(c1, c2){
+ if(!c1.length){
+ return c2;
+ }
+ for(var i = 0, len = c1.length; i < len; i++){
+ addAttr(c1[i], '_qdiff', true);
+ }
+ var r = [];
+ for(var i = 0, len = c2.length; i < len; i++){
+ if(!getAttr(c2[i], '_qdiff')){
+ r[r.length] = c2[i];
+ }
+ }
+ for(var i = 0, len = c1.length; i < len; i++){
+ clearAttr(c1[i], '_qdiff');
+ }
+ return r;
+ }
+
+ function quickId(ns, mode, root, id){
+ if(ns == root){
+ var d = root.ownerDocument || root;
+ return d.getElementById(id);
+ }
+ ns = getNodes(ns, mode, '*');
+ return byId(ns, null, id);
+ }
+
+ return {
+ getStyle : function(el, name){
+ return YAHOO.util.Dom.getStyle(el, name);
+ },
+ /**
+ * Compiles a selector/xpath query into a reusable function. The returned function
+ * takes one parameter "root" (optional), which is the context node from where the query should start.
+ * @param {String} selector The selector/xpath query
+ * @param {String} type (optional) Either 'select' (the default) or 'simple' for a simple selector match
+ * @return {Function}
+ */
+ compile : function(path, type){
+ // strip leading slashes
+ while(path.substr(0, 1)=='/'){
+ path = path.substr(1);
+ }
+ type = type || 'select';
+
+ var fn = ['var f = function(root){\n var mode; var n = root || document;\n'];
+ var q = path, mode, lq;
+ var tk = Clipperz.YUI.DomQuery.matchers;
+ var tklen = tk.length;
+ var mm;
+ while(q && lq != q){
+ lq = q;
+ var tm = q.match(/^(#)?([\w-\*]+)/);
+ if(type == 'select'){
+ if(tm){
+ if(tm[1] == '#'){
+ fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
+ }else{
+ fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
+ }
+ q = q.replace(tm[0], '');
+ }else{
+ fn[fn.length] = 'n = getNodes(n, mode, "*");';
+ }
+ }else{
+ if(tm){
+ if(tm[1] == '#'){
+ fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
+ }else{
+ fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
+ }
+ q = q.replace(tm[0], '');
+ }
+ }
+ while(!(mm = q.match(modeRe))){
+ var matched = false;
+ for(var j = 0; j < tklen; j++){
+ var t = tk[j];
+ var m = q.match(t.re);
+ if(m){
+ fn[fn.length] = t.select.replace(tplRe, function(x, i){
+ return m[i];
+ });
+ q = q.replace(m[0], '');
+ matched = true;
+ break;
+ }
+ }
+ // prevent infinite loop on bad selector
+ if(!matched){
+ throw 'Error parsing selector, parsing failed at "' + q + '"';
+ }
+ }
+ if(mm[1]){
+ fn[fn.length] = 'mode="'+mm[1]+'";';
+ q = q.replace(mm[1], '');
+ }
+ }
+ fn[fn.length] = 'return nodup(n);\n}';
+ eval(fn.join(''));
+ return f;
+ },
+
+ /**
+ * Selects a group of elements.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @return {Array}
+ */
+ select : function(path, root, type){
+ if(!root || root == document){
+ root = document;
+ }
+ if(typeof root == 'string'){
+ root = document.getElementById(root);
+ }
+ var paths = path.split(',');
+ var results = [];
+ for(var i = 0, len = paths.length; i < len; i++){
+ var p = paths[i].replace(trimRe, '$1');
+ if(!cache[p]){
+ cache[p] = Clipperz.YUI.DomQuery.compile(p);
+ if(!cache[p]){
+ throw p + ' is not a valid selector';
+ }
+ }
+ var result = cache[p](root);
+ if(result && result != document){
+ results = results.concat(result);
+ }
+ }
+ return results;
+ },
+
+ /**
+ * Selects a single element.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @return {Element}
+ */
+ selectNode : function(path, root){
+ return Clipperz.YUI.DomQuery.select(path, root)[0];
+ },
+
+ /**
+ * Selects the value of a node, optionally replacing null with the defaultValue.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @param {String} defaultValue
+ */
+ selectValue : function(path, root, defaultValue){
+ path = path.replace(trimRe, '$1');
+ if(!valueCache[path]){
+ valueCache[path] = Clipperz.YUI.DomQuery.compile(path, 'simple');
+ }
+ var n = valueCache[path](root);
+ n = n[0] ? n[0] : n;
+ var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
+ return (v === null ? defaultValue : v);
+ },
+
+ /**
+ * Selects the value of a node, parsing integers and floats.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @param {Number} defaultValue
+ * @return {Number}
+ */
+ selectNumber : function(path, root, defaultValue){
+ var v = Clipperz.YUI.DomQuery.selectValue(path, root, defaultValue || 0);
+ return parseFloat(v);
+ },
+
+ /**
+ * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
+ * @param {String/HTMLElement/Array} el An element id, element or array of elements
+ * @param {String} selector The simple selector to test
+ * @return {Boolean}
+ */
+ is : function(el, ss){
+ if(typeof el == 'string'){
+ el = document.getElementById(el);
+ }
+ var isArray = (el instanceof Array);
+ var result = Clipperz.YUI.DomQuery.filter(isArray ? el : [el], ss);
+ return isArray ? (result.length == el.length) : (result.length > 0);
+ },
+
+ /**
+ * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
+ * @param {Array} el An array of elements to filter
+ * @param {String} selector The simple selector to test
+ * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
+ * the selector instead of the ones that match
+ * @return {Array}
+ */
+ filter : function(els, ss, nonMatches){
+ ss = ss.replace(trimRe, '$1');
+ if(!simpleCache[ss]){
+ simpleCache[ss] = Clipperz.YUI.DomQuery.compile(ss, 'simple');
+ }
+ var result = simpleCache[ss](els);
+ return nonMatches ? quickDiff(result, els) : result;
+ },
+
+ /**
+ * Collection of matching regular expressions and code snippets.
+ */
+ matchers : [{
+ re: /^\.([\w-]+)/,
+ select: 'n = byClassName(n, null, "{1}");'
+ }, {
+ re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
+ select: 'n = byPseudo(n, "{1}", "{2}");'
+ },{
+ re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
+ select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
+ }, {
+ re: /^#([\w-]+)/,
+ select: 'n = byId(n, null, "{1}");'
+ },{
+ re: /^@([\w-]+)/,
+ select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
+ }
+ ],
+
+ /**
+ * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *= and %=.
+ * New operators can be added as long as the match the format c= where c is any character other than space, > <.
+ */
+ operators : {
+ '=' : function(a, v){
+ return a == v;
+ },
+ '!=' : function(a, v){
+ return a != v;
+ },
+ '^=' : function(a, v){
+ return a && a.substr(0, v.length) == v;
+ },
+ '$=' : function(a, v){
+ return a && a.substr(a.length-v.length) == v;
+ },
+ '*=' : function(a, v){
+ return a && a.indexOf(v) !== -1;
+ },
+ '%=' : function(a, v){
+ return (a % v) == 0;
+ }
+ },
+
+ /**
+ * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
+ * and the argument (if any) supplied in the selector.
+ */
+ pseudos : {
+ 'first-child' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!prev(ci)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'last-child' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!next(ci)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'nth-child' : function(c, a){
+ var r = [];
+ if(a != 'odd' && a != 'even'){
+ for(var i = 0, ci; ci = c[i]; i++){
+ var m = child(ci.parentNode, a);
+ if(m == ci){
+ r[r.length] = m;
+ }
+ }
+ return r;
+ }
+ var p;
+ // first let's clean up the parent nodes
+ for(var i = 0, l = c.length; i < l; i++){
+ var cp = c[i].parentNode;
+ if(cp != p){
+ clean(cp);
+ p = cp;
+ }
+ }
+ // then lets see if we match
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i], m = false;
+ if(a == 'odd'){
+ m = ((ci.nodeIndex+1) % 2 == 1);
+ }else if(a == 'even'){
+ m = ((ci.nodeIndex+1) % 2 == 0);
+ }
+ if(m){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'only-child' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!prev(ci) && !next(ci)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'empty' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!ci.firstChild){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'contains' : function(c, v){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(ci.innerHTML.indexOf(v) !== -1){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'checked' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ if(c[i].checked == 'checked'){
+ r[r.length] = c[i];
+ }
+ }
+ return r;
+ },
+
+ 'not' : function(c, ss){
+ return Clipperz.YUI.DomQuery.filter(c, ss, true);
+ },
+
+ 'odd' : function(c){
+ return this['nth-child'](c, 'odd');
+ },
+
+ 'even' : function(c){
+ return this['nth-child'](c, 'even');
+ },
+
+ 'nth' : function(c, a){
+ return c[a-1];
+ },
+
+ 'first' : function(c){
+ return c[0];
+ },
+
+ 'last' : function(c){
+ return c[c.length-1];
+ },
+
+ 'has' : function(c, ss){
+ var s = Clipperz.YUI.DomQuery.select;
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ if(s(ss, ci).length > 0){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'next' : function(c, ss){
+ var is = Clipperz.YUI.DomQuery.is;
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ var n = next(ci);
+ if(n && is(n, ss)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'prev' : function(c, ss){
+ var is = Clipperz.YUI.DomQuery.is;
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ var n = prev(ci);
+ if(n && is(n, ss)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ }
+ }
+ };
+}();
+
+/**
+ * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Clipperz.YUI.DomQuery#select}
+ * @param {String} path The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @return {Array}
+ * @member Ext
+ * @method query
+ */
+Clipperz.YUI.query = Clipperz.YUI.DomQuery.select;
diff --git a/frontend/delta/js/Clipperz/YUI/Utils.js b/frontend/delta/js/Clipperz/YUI/Utils.js
new file mode 100644
index 0000000..4def842
--- /dev/null
+++ b/frontend/delta/js/Clipperz/YUI/Utils.js
@@ -0,0 +1,93 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+if (typeof YAHOO == 'undefined') { YAHOO = {}; };
+if (typeof YAHOO.util == 'undefined') { YAHOO.util = {}; };
+if (typeof YAHOO.util.Dom == 'undefined') { YAHOO.util.Dom = {}; };
+
+YAHOO.extend = function(subc, superc, overrides) {
+ var F = function() {};
+ F.prototype=superc.prototype;
+ subc.prototype=new F();
+ subc.prototype.constructor=subc;
+ subc.superclass=superc.prototype;
+ if (superc.prototype.constructor == Object.prototype.constructor) {
+ superc.prototype.constructor=superc;
+ }
+
+ if (overrides) {
+ for (var i in overrides) {
+ subc.prototype[i]=overrides[i];
+ }
+ }
+};
+
+YAHOO.override = function(origclass, overrides){
+ if(overrides){
+ var p = origclass.prototype;
+ for(var method in overrides){
+ p[method] = overrides[method];
+ }
+ }
+};
+
+YAHOO.extendX = function(subclass, superclass, overrides){
+ YAHOO.extend(subclass, superclass);
+ subclass.override = function(o){
+ YAHOO.override(subclass, o);
+ };
+ if(!subclass.prototype.override){
+ subclass.prototype.override = function(o){
+ for(var method in o){
+ this[method] = o[method];
+ }
+ };
+ }
+ if(overrides){
+ subclass.override(overrides);
+ };
+
+};
+
+YAHOO.util.Dom.get = function(el) {
+ if (!el) { return null; } // nothing to work with
+
+ if (typeof el != 'string' && !(el instanceof Array) ) { // assuming HTMLElement or HTMLCollection, so pass back as is
+ return el;
+ }
+
+ if (typeof el == 'string') { // ID
+ return document.getElementById(el);
+ }
+ else { // array of ID's and/or elements
+ var collection = [];
+ for (var i = 0, len = el.length; i < len; ++i) {
+ collection[collection.length] = YAHOO.util.Dom.get(el[i]);
+ }
+
+ return collection;
+ }
+
+ return null; // safety, should never happen
+};
+
diff --git a/frontend/delta/js/Cubiq/add2home.js b/frontend/delta/js/Cubiq/add2home.js
new file mode 100644
index 0000000..7ecb3c0
--- /dev/null
+++ b/frontend/delta/js/Cubiq/add2home.js
@@ -0,0 +1,365 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/*!
+ * Add to Homescreen v2.0.8 ~ Copyright (c) 2013 Matteo Spinelli, http://cubiq.org
+ * Released under MIT license, http://cubiq.org/license
+ */
+var addToHome = (function (w) {
+ var nav = w.navigator,
+ isIDevice = 'platform' in nav && (/iphone|ipod|ipad/gi).test(nav.platform),
+ isIPad,
+ isRetina,
+ isSafari,
+ isStandalone,
+ OSVersion,
+ startX = 0,
+ startY = 0,
+ lastVisit = 0,
+ isExpired,
+ isSessionActive,
+ isReturningVisitor,
+ balloon,
+ overrideChecks,
+
+ positionInterval,
+ closeTimeout,
+
+ options = {
+ autostart: true, // Automatically open the balloon
+ returningVisitor: false, // Show the balloon to returning visitors only (setting this to true is highly recommended)
+ animationIn: 'drop', // drop || bubble || fade
+ animationOut: 'fade', // drop || bubble || fade
+ startDelay: 2000, // 2 seconds from page load before the balloon appears
+ lifespan: 15000, // 15 seconds before it is automatically destroyed
+ bottomOffset: 14, // Distance of the balloon from bottom
+ expire: 0, // Minutes to wait before showing the popup again (0 = always displayed)
+ message: '', // Customize your message or force a language ('' = automatic)
+ touchIcon: false, // Display the touch icon
+ arrow: true, // Display the balloon arrow
+ hookOnLoad: true, // Should we hook to onload event? (really advanced usage)
+ closeButton: true, // Let the user close the balloon
+ iterations: 100 // Internal/debug use
+ },
+
+ intl = {
+ ar: 'قم بتثبيت هذا التطبيق على %device:انقر%icon ،ثم اضفه الى الشاشة الرئيسية.',
+ ca_es: 'Per instal·lar aquesta aplicació al vostre %device premeu %icon i llavors Afegir a pantalla d\'inici.',
+ cs_cz: 'Pro instalaci aplikace na Váš %device, stiskněte %icon a v nabídce Přidat na plochu.',
+ da_dk: 'Tilføj denne side til din %device: tryk på %icon og derefter Føj til hjemmeskærm.',
+ de_de: 'Installieren Sie diese App auf Ihrem %device: %icon antippen und dann Zum Home-Bildschirm.',
+ el_gr: 'Εγκαταστήσετε αυτήν την Εφαρμογή στήν συσκευή σας %device: %icon μετά πατάτε Προσθήκη σε Αφετηρία.',
+ en_us: 'Install this web app on your %device: tap %icon and then Add to Home Screen.',
+ es_es: 'Para instalar esta app en su %device, pulse %icon y seleccione Añadir a pantalla de inicio.',
+ fi_fi: 'Asenna tämä web-sovellus laitteeseesi %device: paina %icon ja sen jälkeen valitse Lisää Koti-valikkoon.',
+ fr_fr: 'Ajoutez cette application sur votre %device en cliquant sur %icon, puis Ajouter à l\'écran d\'accueil.',
+ he_il: 'התקן אפליקציה זו על ה-%device שלך: הקש %icon ואז הוסף למסך הבית.',
+ hr_hr: 'Instaliraj ovu aplikaciju na svoj %device: klikni na %icon i odaberi Dodaj u početni zaslon.',
+ hu_hu: 'Telepítse ezt a web-alkalmazást az Ön %device-jára: nyomjon a %icon-ra majd a Főképernyőhöz adás gombra.',
+ it_it: 'Installa questa applicazione sul tuo %device: premi su %icon e poi Aggiungi a Home.',
+ ja_jp: 'このウェブアプリをあなたの%deviceにインストールするには%iconをタップしてホーム画面に追加を選んでください。',
+ ko_kr: '%device에 웹앱을 설치하려면 %icon을 터치 후 "홈화면에 추가"를 선택하세요',
+ nb_no: 'Installer denne appen på din %device: trykk på %icon og deretter Legg til på Hjem-skjerm',
+ nl_nl: 'Installeer deze webapp op uw %device: tik %icon en dan Voeg toe aan beginscherm.',
+ pl_pl: 'Aby zainstalować tę aplikacje na %device: naciśnij %icon a następnie Dodaj jako ikonę.',
+ pt_br: 'Instale este aplicativo em seu %device: aperte %icon e selecione Adicionar à Tela Inicio.',
+ pt_pt: 'Para instalar esta aplicação no seu %device, prima o %icon e depois em Adicionar ao ecrã principal.',
+ ru_ru: 'Установите это веб-приложение на ваш %device: нажмите %icon, затем Добавить в «Домой».',
+ sv_se: 'Lägg till denna webbapplikation på din %device: tryck på %icon och därefter Lägg till på hemskärmen.',
+ th_th: 'ติดตั้งเว็บแอพฯ นี้บน %device ของคุณ: แตะ %icon และ เพิ่มที่หน้าจอโฮม',
+ tr_tr: 'Bu uygulamayı %device\'a eklemek için %icon simgesine sonrasında Ana Ekrana Ekle düğmesine basın.',
+ uk_ua: 'Встановіть цей веб сайт на Ваш %device: натисніть %icon, а потім На початковий екран.',
+ zh_cn: '您可以将此应用程式安装到您的 %device 上。请按 %icon 然后点选添加至主屏幕。',
+ zh_tw: '您可以將此應用程式安裝到您的 %device 上。請按 %icon 然後點選加入主畫面螢幕。'
+ };
+
+ function init () {
+ // Preliminary check, all further checks are performed on iDevices only
+ if ( !isIDevice ) return;
+
+ var now = Date.now(),
+ i;
+
+ // Merge local with global options
+ if ( w.addToHomeConfig ) {
+ for ( i in w.addToHomeConfig ) {
+ options[i] = w.addToHomeConfig[i];
+ }
+ }
+ if ( !options.autostart ) options.hookOnLoad = false;
+
+ isIPad = (/ipad/gi).test(nav.platform);
+ isRetina = w.devicePixelRatio && w.devicePixelRatio > 1;
+ isSafari = (/Safari/i).test(nav.appVersion) && !(/CriOS/i).test(nav.appVersion);
+ isStandalone = nav.standalone;
+ OSVersion = nav.appVersion.match(/OS (\d+_\d+)/i);
+ OSVersion = OSVersion && OSVersion[1] ? +OSVersion[1].replace('_', '.') : 0;
+
+ lastVisit = +w.localStorage.getItem('addToHome');
+
+ isSessionActive = w.sessionStorage.getItem('addToHomeSession');
+ isReturningVisitor = options.returningVisitor ? lastVisit && lastVisit + 28*24*60*60*1000 > now : true;
+
+ if ( !lastVisit ) lastVisit = now;
+
+ // If it is expired we need to reissue a new balloon
+ isExpired = isReturningVisitor && lastVisit <= now;
+
+ if ( options.hookOnLoad ) w.addEventListener('load', loaded, false);
+ else if ( !options.hookOnLoad && options.autostart ) loaded();
+ }
+
+ function loaded () {
+ w.removeEventListener('load', loaded, false);
+
+ if ( !isReturningVisitor ) w.localStorage.setItem('addToHome', Date.now());
+ else if ( options.expire && isExpired ) w.localStorage.setItem('addToHome', Date.now() + options.expire * 60000);
+
+ if ( !overrideChecks && ( !isSafari || !isExpired || isSessionActive || isStandalone || !isReturningVisitor ) ) return;
+
+ var touchIcon = '',
+ platform = nav.platform.split(' ')[0],
+ language = nav.language.replace('-', '_');
+
+ balloon = document.createElement('div');
+ balloon.id = 'addToHomeScreen';
+ balloon.style.cssText += 'left:-9999px;-webkit-transition-property:-webkit-transform,opacity;-webkit-transition-duration:0;-webkit-transform:translate3d(0,0,0);position:' + (OSVersion < 5 ? 'absolute' : 'fixed');
+
+ // Localize message
+ if ( options.message in intl ) { // You may force a language despite the user's locale
+ language = options.message;
+ options.message = '';
+ }
+ if ( options.message === '' ) { // We look for a suitable language (defaulted to en_us)
+ options.message = language in intl ? intl[language] : intl['en_us'];
+ }
+
+ if ( options.touchIcon ) {
+ touchIcon = isRetina ?
+ document.querySelector('head link[rel^=apple-touch-icon][sizes="114x114"],head link[rel^=apple-touch-icon][sizes="144x144"],head link[rel^=apple-touch-icon]') :
+ document.querySelector('head link[rel^=apple-touch-icon][sizes="57x57"],head link[rel^=apple-touch-icon]');
+
+ if ( touchIcon ) {
+ touchIcon = '';
+ }
+ }
+
+ balloon.className = (isIPad ? 'addToHomeIpad' : 'addToHomeIphone') + (touchIcon ? ' addToHomeWide' : '');
+ balloon.innerHTML = touchIcon +
+ options.message.replace('%device', platform).replace('%icon', OSVersion >= 4.2 ? '' : '+') +
+ (options.arrow ? '' : '') +
+ (options.closeButton ? '\u00D7' : '');
+
+ document.body.appendChild(balloon);
+
+ // Add the close action
+ if ( options.closeButton ) balloon.addEventListener('click', clicked, false);
+
+ if ( !isIPad && OSVersion >= 6 ) window.addEventListener('orientationchange', orientationCheck, false);
+
+ setTimeout(show, options.startDelay);
+ }
+
+ function show () {
+ var duration,
+ iPadXShift = 208;
+
+ // Set the initial position
+ if ( isIPad ) {
+ if ( OSVersion < 5 ) {
+ startY = w.scrollY;
+ startX = w.scrollX;
+ } else if ( OSVersion < 6 ) {
+ iPadXShift = 160;
+ }
+
+ balloon.style.top = startY + options.bottomOffset + 'px';
+ balloon.style.left = startX + iPadXShift - Math.round(balloon.offsetWidth / 2) + 'px';
+
+ switch ( options.animationIn ) {
+ case 'drop':
+ duration = '0.6s';
+ balloon.style.webkitTransform = 'translate3d(0,' + -(w.scrollY + options.bottomOffset + balloon.offsetHeight) + 'px,0)';
+ break;
+ case 'bubble':
+ duration = '0.6s';
+ balloon.style.opacity = '0';
+ balloon.style.webkitTransform = 'translate3d(0,' + (startY + 50) + 'px,0)';
+ break;
+ default:
+ duration = '1s';
+ balloon.style.opacity = '0';
+ }
+ } else {
+ startY = w.innerHeight + w.scrollY;
+
+ if ( OSVersion < 5 ) {
+ startX = Math.round((w.innerWidth - balloon.offsetWidth) / 2) + w.scrollX;
+ balloon.style.left = startX + 'px';
+ balloon.style.top = startY - balloon.offsetHeight - options.bottomOffset + 'px';
+ } else {
+ balloon.style.left = '50%';
+ balloon.style.marginLeft = -Math.round(balloon.offsetWidth / 2) - ( w.orientation%180 && OSVersion >= 6 ? 40 : 0 ) + 'px';
+ balloon.style.bottom = options.bottomOffset + 'px';
+ }
+
+ switch (options.animationIn) {
+ case 'drop':
+ duration = '1s';
+ balloon.style.webkitTransform = 'translate3d(0,' + -(startY + options.bottomOffset) + 'px,0)';
+ break;
+ case 'bubble':
+ duration = '0.6s';
+ balloon.style.webkitTransform = 'translate3d(0,' + (balloon.offsetHeight + options.bottomOffset + 50) + 'px,0)';
+ break;
+ default:
+ duration = '1s';
+ balloon.style.opacity = '0';
+ }
+ }
+
+ balloon.offsetHeight; // repaint trick
+ balloon.style.webkitTransitionDuration = duration;
+ balloon.style.opacity = '1';
+ balloon.style.webkitTransform = 'translate3d(0,0,0)';
+ balloon.addEventListener('webkitTransitionEnd', transitionEnd, false);
+
+ closeTimeout = setTimeout(close, options.lifespan);
+ }
+
+ function manualShow (override) {
+ if ( !isIDevice || balloon ) return;
+
+ overrideChecks = override;
+ loaded();
+ }
+
+ function close () {
+ clearInterval( positionInterval );
+ clearTimeout( closeTimeout );
+ closeTimeout = null;
+
+ // check if the popup is displayed and prevent errors
+ if ( !balloon ) return;
+
+ var posY = 0,
+ posX = 0,
+ opacity = '1',
+ duration = '0';
+
+ if ( options.closeButton ) balloon.removeEventListener('click', clicked, false);
+ if ( !isIPad && OSVersion >= 6 ) window.removeEventListener('orientationchange', orientationCheck, false);
+
+ if ( OSVersion < 5 ) {
+ posY = isIPad ? w.scrollY - startY : w.scrollY + w.innerHeight - startY;
+ posX = isIPad ? w.scrollX - startX : w.scrollX + Math.round((w.innerWidth - balloon.offsetWidth)/2) - startX;
+ }
+
+ balloon.style.webkitTransitionProperty = '-webkit-transform,opacity';
+
+ switch ( options.animationOut ) {
+ case 'drop':
+ if ( isIPad ) {
+ duration = '0.4s';
+ opacity = '0';
+ posY += 50;
+ } else {
+ duration = '0.6s';
+ posY += balloon.offsetHeight + options.bottomOffset + 50;
+ }
+ break;
+ case 'bubble':
+ if ( isIPad ) {
+ duration = '0.8s';
+ posY -= balloon.offsetHeight + options.bottomOffset + 50;
+ } else {
+ duration = '0.4s';
+ opacity = '0';
+ posY -= 50;
+ }
+ break;
+ default:
+ duration = '0.8s';
+ opacity = '0';
+ }
+
+ balloon.addEventListener('webkitTransitionEnd', transitionEnd, false);
+ balloon.style.opacity = opacity;
+ balloon.style.webkitTransitionDuration = duration;
+ balloon.style.webkitTransform = 'translate3d(' + posX + 'px,' + posY + 'px,0)';
+ }
+
+
+ function clicked () {
+ w.sessionStorage.setItem('addToHomeSession', '1');
+ isSessionActive = true;
+ close();
+ }
+
+ function transitionEnd () {
+ balloon.removeEventListener('webkitTransitionEnd', transitionEnd, false);
+
+ balloon.style.webkitTransitionProperty = '-webkit-transform';
+ balloon.style.webkitTransitionDuration = '0.2s';
+
+ // We reached the end!
+ if ( !closeTimeout ) {
+ balloon.parentNode.removeChild(balloon);
+ balloon = null;
+ return;
+ }
+
+ // On iOS 4 we start checking the element position
+ if ( OSVersion < 5 && closeTimeout ) positionInterval = setInterval(setPosition, options.iterations);
+ }
+
+ function setPosition () {
+ var matrix = new WebKitCSSMatrix(w.getComputedStyle(balloon, null).webkitTransform),
+ posY = isIPad ? w.scrollY - startY : w.scrollY + w.innerHeight - startY,
+ posX = isIPad ? w.scrollX - startX : w.scrollX + Math.round((w.innerWidth - balloon.offsetWidth) / 2) - startX;
+
+ // Screen didn't move
+ if ( posY == matrix.m42 && posX == matrix.m41 ) return;
+
+ balloon.style.webkitTransform = 'translate3d(' + posX + 'px,' + posY + 'px,0)';
+ }
+
+ // Clear local and session storages (this is useful primarily in development)
+ function reset () {
+ w.localStorage.removeItem('addToHome');
+ w.sessionStorage.removeItem('addToHomeSession');
+ }
+
+ function orientationCheck () {
+ balloon.style.marginLeft = -Math.round(balloon.offsetWidth / 2) - ( w.orientation%180 && OSVersion >= 6 ? 40 : 0 ) + 'px';
+ }
+
+ // Bootstrap!
+ init();
+
+ return {
+ show: manualShow,
+ close: close,
+ reset: reset
+ };
+})(window);
diff --git a/frontend/delta/js/MochiKit/Async.js b/frontend/delta/js/MochiKit/Async.js
new file mode 100644
index 0000000..a76aaa2
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Async.js
@@ -0,0 +1,733 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Async 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Async', '1.5', ['Base']);
+
+/** @id MochiKit.Async.Deferred */
+MochiKit.Async.Deferred = function (/* optional */ canceller) {
+ this.chain = [];
+ this.id = this._nextId();
+ this.fired = -1;
+ this.paused = 0;
+ this.results = [null, null];
+ this.canceller = canceller;
+ this.silentlyCancelled = false;
+ this.chained = false;
+ this.finalized = false;
+};
+
+MochiKit.Async.Deferred.prototype = {
+ /** @id MochiKit.Async.Deferred.prototype.repr */
+ repr: function () {
+ return 'Deferred(' + this.id + ', ' + this.state() + ')';
+ },
+
+ toString: MochiKit.Base.forwardCall("repr"),
+
+ _nextId: MochiKit.Base.counter(),
+
+ /** @id MochiKit.Async.Deferred.prototype.state */
+ state: function () {
+ if (this.fired == -1) {
+ return 'unfired';
+ } else if (this.fired === 0) {
+ return 'success';
+ } else {
+ return 'error';
+ }
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.cancel */
+ cancel: function (e) {
+ var self = MochiKit.Async;
+ if (this.fired == -1) {
+ if (this.canceller) {
+ this.canceller(this);
+ } else {
+ this.silentlyCancelled = true;
+ }
+ if (this.fired == -1) {
+ if (typeof(e) === 'string') {
+ e = new self.GenericError(e);
+ } else if (!(e instanceof Error)) {
+ e = new self.CancelledError(this);
+ }
+ this.errback(e);
+ }
+ } else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
+ this.results[0].cancel(e);
+ }
+ },
+
+ _resback: function (res) {
+ /***
+
+ The primitive that means either callback or errback
+
+ ***/
+ this.fired = ((res instanceof Error) ? 1 : 0);
+ this.results[this.fired] = res;
+ if (this.paused === 0) {
+ this._fire();
+ }
+ },
+
+ _check: function () {
+ if (this.fired != -1) {
+ if (!this.silentlyCancelled) {
+ throw new MochiKit.Async.AlreadyCalledError(this);
+ }
+ this.silentlyCancelled = false;
+ return;
+ }
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.callback */
+ callback: function (res) {
+ this._check();
+ if (res instanceof MochiKit.Async.Deferred) {
+ throw new Error("Deferred instances can only be chained if they are the result of a callback");
+ }
+ this._resback(res);
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.errback */
+ errback: function (res) {
+ this._check();
+ var self = MochiKit.Async;
+ if (res instanceof self.Deferred) {
+ throw new Error("Deferred instances can only be chained if they are the result of a callback");
+ }
+ if (!(res instanceof Error)) {
+ res = new self.GenericError(res);
+ }
+ this._resback(res);
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.addBoth */
+ addBoth: function (fn) {
+ if (arguments.length > 1) {
+ fn = MochiKit.Base.partial.apply(null, arguments);
+ }
+ return this.addCallbacks(fn, fn);
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.addCallback */
+ addCallback: function (fn) {
+ if (arguments.length > 1) {
+ fn = MochiKit.Base.partial.apply(null, arguments);
+ }
+ return this.addCallbacks(fn, null);
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.addErrback */
+ addErrback: function (fn) {
+ if (arguments.length > 1) {
+ fn = MochiKit.Base.partial.apply(null, arguments);
+ }
+ return this.addCallbacks(null, fn);
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.addCallbacks */
+ addCallbacks: function (cb, eb) {
+ if (this.chained) {
+ throw new Error("Chained Deferreds can not be re-used");
+ }
+ if (this.finalized) {
+ throw new Error("Finalized Deferreds can not be re-used");
+ }
+ this.chain.push([cb, eb]);
+ if (this.fired >= 0) {
+ this._fire();
+ }
+ return this;
+ },
+
+ /** @id MochiKit.Async.Deferred.prototype.setFinalizer */
+ setFinalizer: function (fn) {
+ if (this.chained) {
+ throw new Error("Chained Deferreds can not be re-used");
+ }
+ if (this.finalized) {
+ throw new Error("Finalized Deferreds can not be re-used");
+ }
+ if (arguments.length > 1) {
+ fn = MochiKit.Base.partial.apply(null, arguments);
+ }
+ this._finalizer = fn;
+ if (this.fired >= 0) {
+ this._fire();
+ }
+ return this;
+ },
+
+ _fire: function () {
+ /***
+
+ Used internally to exhaust the callback sequence when a result
+ is available.
+
+ ***/
+ var chain = this.chain;
+ var fired = this.fired;
+ var res = this.results[fired];
+ var self = this;
+ var cb = null;
+ while (chain.length > 0 && this.paused === 0) {
+ // Array
+ var pair = chain.shift();
+ var f = pair[fired];
+ if (f === null) {
+ continue;
+ }
+ try {
+ res = f(res);
+ fired = ((res instanceof Error) ? 1 : 0);
+ if (res instanceof MochiKit.Async.Deferred) {
+ cb = function (res) {
+ self.paused--;
+ self._resback(res);
+ };
+ this.paused++;
+ }
+ } catch (err) {
+ fired = 1;
+ if (!(err instanceof Error)) {
+ err = new MochiKit.Async.GenericError(err);
+ }
+ res = err;
+ }
+ }
+ this.fired = fired;
+ this.results[fired] = res;
+ if (this.chain.length == 0 && this.paused === 0 && this._finalizer) {
+ this.finalized = true;
+ this._finalizer(res);
+ }
+ if (cb && this.paused) {
+ // this is for "tail recursion" in case the dependent deferred
+ // is already fired
+ res.addBoth(cb);
+ res.chained = true;
+ }
+ }
+};
+
+MochiKit.Base.update(MochiKit.Async, {
+ /** @id MochiKit.Async.evalJSONRequest */
+ evalJSONRequest: function (req) {
+ return MochiKit.Base.evalJSON(req.responseText);
+ },
+
+ /** @id MochiKit.Async.succeed */
+ succeed: function (/* optional */result) {
+ var d = new MochiKit.Async.Deferred();
+ d.callback.apply(d, arguments);
+ return d;
+ },
+
+ /** @id MochiKit.Async.fail */
+ fail: function (/* optional */result) {
+ var d = new MochiKit.Async.Deferred();
+ d.errback.apply(d, arguments);
+ return d;
+ },
+
+ /** @id MochiKit.Async.getXMLHttpRequest */
+ getXMLHttpRequest: function () {
+ var self = arguments.callee;
+ if (!self.XMLHttpRequest) {
+ var tryThese = [
+ function () { return new XMLHttpRequest(); },
+ function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
+ function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
+ function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
+ function () {
+ throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
+ }
+ ];
+ for (var i = 0; i < tryThese.length; i++) {
+ var func = tryThese[i];
+ try {
+ self.XMLHttpRequest = func;
+ return func();
+ } catch (e) {
+ // pass
+ }
+ }
+ }
+ return self.XMLHttpRequest();
+ },
+
+ _xhr_onreadystatechange: function (d) {
+ // MochiKit.Logging.logDebug('this.readyState', this.readyState);
+ var m = MochiKit.Base;
+ if (this.readyState == 4) {
+ // IE SUCKS
+ try {
+ this.onreadystatechange = null;
+ } catch (e) {
+ try {
+ this.onreadystatechange = m.noop;
+ } catch (e) {
+ }
+ }
+ var status = null;
+ try {
+ status = this.status;
+ if (!status && (this.response || m.isNotEmpty(this.responseText))) {
+ // 0 or undefined seems to mean cached or local
+ status = 304;
+ }
+ } catch (e) {
+ // pass
+ // MochiKit.Logging.logDebug('error getting status?', repr(items(e)));
+ }
+ // 200 is OK, 201 is CREATED, 204 is NO CONTENT
+ // 304 is NOT MODIFIED, 1223 is apparently a bug in IE
+ if (status == 200 || status == 201 || status == 204 ||
+ status == 304 || status == 1223) {
+ d.callback(this);
+ } else {
+ var err = new MochiKit.Async.XMLHttpRequestError(this, "Request failed");
+ if (err.number) {
+ // XXX: This seems to happen on page change
+ d.errback(err);
+ } else {
+ // XXX: this seems to happen when the server is unreachable
+ d.errback(err);
+ }
+ }
+ }
+ },
+
+ _xhr_canceller: function (req) {
+ // IE SUCKS
+ try {
+ req.onreadystatechange = null;
+ } catch (e) {
+ try {
+ req.onreadystatechange = MochiKit.Base.noop;
+ } catch (e) {
+ }
+ }
+ req.abort();
+ },
+
+
+ /** @id MochiKit.Async.sendXMLHttpRequest */
+ sendXMLHttpRequest: function (req, /* optional */ sendContent) {
+ if (typeof(sendContent) == "undefined" || sendContent === null) {
+ sendContent = "";
+ }
+
+ var m = MochiKit.Base;
+ var self = MochiKit.Async;
+ var d = new self.Deferred(m.partial(self._xhr_canceller, req));
+
+ try {
+ req.onreadystatechange = m.bind(self._xhr_onreadystatechange,
+ req, d);
+ req.send(sendContent);
+ } catch (e) {
+ try {
+ req.onreadystatechange = null;
+ } catch (ignore) {
+ // pass
+ }
+ d.errback(e);
+ }
+
+ return d;
+
+ },
+
+ /** @id MochiKit.Async.doXHR */
+ doXHR: function (url, opts) {
+ /*
+ Work around a Firefox bug by dealing with XHR during
+ the next event loop iteration. Maybe it's this one:
+ https://bugzilla.mozilla.org/show_bug.cgi?id=249843
+ */
+ var self = MochiKit.Async;
+ return self.callLater(0, self._doXHR, url, opts);
+ },
+
+ _doXHR: function (url, opts) {
+ var m = MochiKit.Base;
+ opts = m.update({
+ method: 'GET',
+ sendContent: ''
+ /*
+ queryString: undefined,
+ username: undefined,
+ password: undefined,
+ headers: undefined,
+ mimeType: undefined,
+ responseType: undefined,
+ withCredentials: undefined
+ */
+ }, opts);
+ var self = MochiKit.Async;
+ var req = self.getXMLHttpRequest();
+ if (opts.queryString) {
+ var qs = m.queryString(opts.queryString);
+ if (qs) {
+ url += "?" + qs;
+ }
+ }
+ // Safari will send undefined:undefined, so we have to check.
+ // We can't use apply, since the function is native.
+ if ('username' in opts) {
+ req.open(opts.method, url, true, opts.username, opts.password);
+ } else {
+ req.open(opts.method, url, true);
+ }
+ if (req.overrideMimeType && opts.mimeType) {
+ req.overrideMimeType(opts.mimeType);
+ }
+ req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+ if (opts.headers) {
+ var headers = opts.headers;
+ if (!m.isArrayLike(headers)) {
+ headers = m.items(headers);
+ }
+ for (var i = 0; i < headers.length; i++) {
+ var header = headers[i];
+ var name = header[0];
+ var value = header[1];
+ req.setRequestHeader(name, value);
+ }
+ }
+ if ("responseType" in opts && "responseType" in req) {
+ req.responseType = opts.responseType;
+ }
+ if (opts.withCredentials) {
+ req.withCredentials = 'true';
+ }
+ return self.sendXMLHttpRequest(req, opts.sendContent);
+ },
+
+ _buildURL: function (url/*, ...*/) {
+ if (arguments.length > 1) {
+ var m = MochiKit.Base;
+ var qs = m.queryString.apply(null, m.extend(null, arguments, 1));
+ if (qs) {
+ return url + "?" + qs;
+ }
+ }
+ return url;
+ },
+
+ /** @id MochiKit.Async.doSimpleXMLHttpRequest */
+ doSimpleXMLHttpRequest: function (url/*, ...*/) {
+ var self = MochiKit.Async;
+ url = self._buildURL.apply(self, arguments);
+ return self.doXHR(url);
+ },
+
+ /** @id MochiKit.Async.loadJSONDoc */
+ loadJSONDoc: function (url/*, ...*/) {
+ var self = MochiKit.Async;
+ url = self._buildURL.apply(self, arguments);
+ var d = self.doXHR(url, {
+ 'mimeType': 'text/plain',
+ 'headers': [['Accept', 'application/json']]
+ });
+ d = d.addCallback(self.evalJSONRequest);
+ return d;
+ },
+
+ /** @id MochiKit.Async.loadScript */
+ loadScript: function (url) {
+ var d = new MochiKit.Async.Deferred();
+ var script = document.createElement("script");
+ script.type = "text/javascript";
+ script.src = url;
+ script.onload = function () {
+ script.onload = null;
+ script.onerror = null;
+ script.onreadystatechange = null;
+ script = null;
+ d.callback();
+ };
+ script.onerror = function (msg) {
+ script.onload = null;
+ script.onerror = null;
+ script.onreadystatechange = null;
+ script = null;
+ msg = "Failed to load script at " + url + ": " + msg;
+ d.errback(new URIError(msg, url));
+ }
+ script.onreadystatechange = function () {
+ if (script.readyState == "loaded" || script.readyState == "complete") {
+ script.onload();
+ } else {
+ // IE doesn't bother to report errors...
+ MochiKit.Async.callLater(10, script.onerror, "Script loading timed out")
+ }
+ };
+ document.getElementsByTagName("head")[0].appendChild(script);
+ return d;
+ },
+
+ /** @id MochiKit.Async.wait */
+ wait: function (seconds, /* optional */value) {
+ var d = new MochiKit.Async.Deferred();
+ var cb = MochiKit.Base.bind("callback", d, value);
+ var timeout = setTimeout(cb, Math.floor(seconds * 1000));
+ d.canceller = function () {
+ try {
+ clearTimeout(timeout);
+ } catch (e) {
+ // pass
+ }
+ };
+ return d;
+ },
+
+ /** @id MochiKit.Async.callLater */
+ callLater: function (seconds, func) {
+ var m = MochiKit.Base;
+ var pfunc = m.partial.apply(m, m.extend(null, arguments, 1));
+ return MochiKit.Async.wait(seconds).addCallback(
+ function (res) { return pfunc(); }
+ );
+ }
+});
+
+
+/** @id MochiKit.Async.DeferredLock */
+MochiKit.Async.DeferredLock = function () {
+ this.waiting = [];
+ this.locked = false;
+ this.id = this._nextId();
+};
+
+MochiKit.Async.DeferredLock.prototype = {
+ __class__: MochiKit.Async.DeferredLock,
+ /** @id MochiKit.Async.DeferredLock.prototype.acquire */
+ acquire: function () {
+ var d = new MochiKit.Async.Deferred();
+ if (this.locked) {
+ this.waiting.push(d);
+ } else {
+ this.locked = true;
+ d.callback(this);
+ }
+ return d;
+ },
+ /** @id MochiKit.Async.DeferredLock.prototype.release */
+ release: function () {
+ if (!this.locked) {
+ throw TypeError("Tried to release an unlocked DeferredLock");
+ }
+ this.locked = false;
+ if (this.waiting.length > 0) {
+ this.locked = true;
+ this.waiting.shift().callback(this);
+ }
+ },
+ _nextId: MochiKit.Base.counter(),
+ repr: function () {
+ var state;
+ if (this.locked) {
+ state = 'locked, ' + this.waiting.length + ' waiting';
+ } else {
+ state = 'unlocked';
+ }
+ return 'DeferredLock(' + this.id + ', ' + state + ')';
+ },
+ toString: MochiKit.Base.forwardCall("repr")
+
+};
+
+/** @id MochiKit.Async.DeferredList */
+MochiKit.Async.DeferredList = function (list, /* optional */fireOnOneCallback, fireOnOneErrback, consumeErrors, canceller) {
+
+ // call parent constructor
+ MochiKit.Async.Deferred.apply(this, [canceller]);
+
+ this.list = list;
+ var resultList = [];
+ this.resultList = resultList;
+
+ this.finishedCount = 0;
+ this.fireOnOneCallback = fireOnOneCallback;
+ this.fireOnOneErrback = fireOnOneErrback;
+ this.consumeErrors = consumeErrors;
+
+ var cb = MochiKit.Base.bind(this._cbDeferred, this);
+ for (var i = 0; i < list.length; i++) {
+ var d = list[i];
+ resultList.push(undefined);
+ d.addCallback(cb, i, true);
+ d.addErrback(cb, i, false);
+ }
+
+ if (list.length === 0 && !fireOnOneCallback) {
+ this.callback(this.resultList);
+ }
+
+};
+
+MochiKit.Async.DeferredList.prototype = new MochiKit.Async.Deferred();
+MochiKit.Async.DeferredList.prototype.constructor = MochiKit.Async.DeferredList;
+
+MochiKit.Async.DeferredList.prototype._cbDeferred = function (index, succeeded, result) {
+ this.resultList[index] = [succeeded, result];
+ this.finishedCount += 1;
+ if (this.fired == -1) {
+ if (succeeded && this.fireOnOneCallback) {
+ this.callback([index, result]);
+ } else if (!succeeded && this.fireOnOneErrback) {
+ this.errback(result);
+ } else if (this.finishedCount == this.list.length) {
+ this.callback(this.resultList);
+ }
+ }
+ if (!succeeded && this.consumeErrors) {
+ result = null;
+ }
+ return result;
+};
+
+/** @id MochiKit.Async.gatherResults */
+MochiKit.Async.gatherResults = function (deferredList) {
+ var d = new MochiKit.Async.DeferredList(deferredList, false, true, false);
+ d.addCallback(function (results) {
+ var ret = [];
+ for (var i = 0; i < results.length; i++) {
+ ret.push(results[i][1]);
+ }
+ return ret;
+ });
+ return d;
+};
+
+/** @id MochiKit.Async.maybeDeferred */
+MochiKit.Async.maybeDeferred = function (func) {
+ var self = MochiKit.Async;
+ var result;
+ try {
+ var r = func.apply(null, MochiKit.Base.extend([], arguments, 1));
+ if (r instanceof self.Deferred) {
+ result = r;
+ } else if (r instanceof Error) {
+ result = self.fail(r);
+ } else {
+ result = self.succeed(r);
+ }
+ } catch (e) {
+ result = self.fail(e);
+ }
+ return result;
+};
+
+
+MochiKit.Async.__new__ = function () {
+ var m = MochiKit.Base;
+ var ne = m.partial(m._newNamedError, this);
+
+ ne("AlreadyCalledError",
+ /** @id MochiKit.Async.AlreadyCalledError */
+ function (deferred) {
+ /***
+
+ Raised by the Deferred if callback or errback happens
+ after it was already fired.
+
+ ***/
+ this.deferred = deferred;
+ }
+ );
+
+ ne("CancelledError",
+ /** @id MochiKit.Async.CancelledError */
+ function (deferred) {
+ /***
+
+ Raised by the Deferred cancellation mechanism.
+
+ ***/
+ this.deferred = deferred;
+ }
+ );
+
+ ne("BrowserComplianceError",
+ /** @id MochiKit.Async.BrowserComplianceError */
+ function (msg) {
+ /***
+
+ Raised when the JavaScript runtime is not capable of performing
+ the given function. Technically, this should really never be
+ raised because a non-conforming JavaScript runtime probably
+ isn't going to support exceptions in the first place.
+
+ ***/
+ this.message = msg;
+ }
+ );
+
+ ne("GenericError",
+ /** @id MochiKit.Async.GenericError */
+ function (msg) {
+ this.message = msg;
+ }
+ );
+
+ ne("XMLHttpRequestError",
+ /** @id MochiKit.Async.XMLHttpRequestError */
+ function (req, msg) {
+ /***
+
+ Raised when an XMLHttpRequest does not complete for any reason.
+
+ ***/
+ this.req = req;
+ this.message = msg;
+ try {
+ // Strange but true that this can raise in some cases.
+ this.number = req.status;
+ } catch (e) {
+ // pass
+ }
+ }
+ );
+
+ m.nameFunctions(this);
+};
+
+MochiKit.Async.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.Async);
diff --git a/frontend/delta/js/MochiKit/Base.js b/frontend/delta/js/MochiKit/Base.js
new file mode 100644
index 0000000..c55f5c3
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Base.js
@@ -0,0 +1,1523 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Base 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+
+// MochiKit module (namespace)
+var MochiKit = MochiKit || {};
+if (typeof(MochiKit.__export__) == "undefined") {
+ MochiKit.__export__ = true;
+}
+MochiKit.NAME = "MochiKit";
+MochiKit.VERSION = "1.5";
+MochiKit.__repr__ = function () {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+};
+MochiKit.toString = function () {
+ return this.__repr__();
+};
+
+
+// MochiKit.Base module
+MochiKit.Base = MochiKit.Base || {};
+
+/**
+ * Creates a new module in a parent namespace. This function will
+ * create a new empty module object with "NAME", "VERSION",
+ * "toString" and "__repr__" properties. This object will be inserted into the parent object
+ * using the specified name (i.e. parent[name] = module). It will
+ * also verify that all the dependency modules are defined in the
+ * parent, or an error will be thrown.
+ *
+ * @param {Object} parent the parent module (use "this" or "window" for
+ * a global module)
+ * @param {String} name the module name, e.g. "Base"
+ * @param {String} version the module version, e.g. "1.5"
+ * @param {Array} [deps] the array of module dependencies (as strings)
+ */
+MochiKit.Base.module = function (parent, name, version, deps) {
+ var module = parent[name] = parent[name] || {};
+ var prefix = (parent.NAME ? parent.NAME + "." : "");
+ module.NAME = prefix + name;
+ module.VERSION = version;
+ module.__repr__ = function () {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+ };
+ module.toString = function () {
+ return this.__repr__();
+ };
+ for (var i = 0; deps != null && i < deps.length; i++) {
+ if (!(deps[i] in parent)) {
+ throw module.NAME + ' depends on ' + prefix + deps[i] + '!';
+ }
+ }
+ return module;
+};
+
+MochiKit.Base.module(MochiKit, "Base", "1.5", []);
+
+/** @id MochiKit.Base.update */
+MochiKit.Base.update = function (self, obj/*, ... */) {
+ if (self === null || self === undefined) {
+ self = {};
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var o = arguments[i];
+ if (typeof(o) != 'undefined' && o !== null) {
+ for (var k in o) {
+ self[k] = o[k];
+ }
+ }
+ }
+ return self;
+};
+
+MochiKit.Base.update(MochiKit.Base, {
+ /** @id MochiKit.Base.camelize */
+ camelize: function (selector) {
+ /* from dojo.style.toCamelCase */
+ var arr = selector.split('-');
+ var cc = arr[0];
+ for (var i = 1; i < arr.length; i++) {
+ cc += arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
+ }
+ return cc;
+ },
+
+ /** @id MochiKit.Base.counter */
+ counter: function (n/* = 1 */) {
+ if (arguments.length === 0) {
+ n = 1;
+ }
+ return function () {
+ return n++;
+ };
+ },
+
+ /** @id MochiKit.Base.clone */
+ clone: function (obj) {
+ var me = arguments.callee;
+ if (arguments.length == 1) {
+ me.prototype = obj;
+ return new me();
+ }
+ },
+
+ _flattenArray: function (res, lst) {
+ for (var i = 0; i < lst.length; i++) {
+ var o = lst[i];
+ if (o instanceof Array) {
+ arguments.callee(res, o);
+ } else {
+ res.push(o);
+ }
+ }
+ return res;
+ },
+
+ /** @id MochiKit.Base.flattenArray */
+ flattenArray: function (lst) {
+ return MochiKit.Base._flattenArray([], lst);
+ },
+
+ /** @id MochiKit.Base.flattenArguments */
+ flattenArguments: function (lst/* ...*/) {
+ var res = [];
+ var m = MochiKit.Base;
+ var args = m.extend(null, arguments);
+ while (args.length) {
+ var o = args.shift();
+ if (o && typeof(o) == "object" && typeof(o.length) == "number") {
+ for (var i = o.length - 1; i >= 0; i--) {
+ args.unshift(o[i]);
+ }
+ } else {
+ res.push(o);
+ }
+ }
+ return res;
+ },
+
+ /** @id MochiKit.Base.extend */
+ extend: function (self, obj, /* optional */skip) {
+ // Extend an array with an array-like object starting
+ // from the skip index
+ if (!skip) {
+ skip = 0;
+ }
+ if (obj) {
+ // allow iterable fall-through, but skip the full isArrayLike
+ // check for speed, this is called often.
+ var l = obj.length;
+ if (typeof(l) != 'number' /* !isArrayLike(obj) */) {
+ if (typeof(MochiKit.Iter) != "undefined") {
+ obj = MochiKit.Iter.list(obj);
+ l = obj.length;
+ } else {
+ throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+ }
+ }
+ if (!self) {
+ self = [];
+ }
+ for (var i = skip; i < l; i++) {
+ self.push(obj[i]);
+ }
+ }
+ // This mutates, but it's convenient to return because
+ // it's often used like a constructor when turning some
+ // ghetto array-like to a real array
+ return self;
+ },
+
+
+ /** @id MochiKit.Base.updatetree */
+ updatetree: function (self, obj/*, ...*/) {
+ if (self === null || self === undefined) {
+ self = {};
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var o = arguments[i];
+ if (typeof(o) != 'undefined' && o !== null) {
+ for (var k in o) {
+ var v = o[k];
+ if (typeof(self[k]) == 'object' && typeof(v) == 'object') {
+ arguments.callee(self[k], v);
+ } else {
+ self[k] = v;
+ }
+ }
+ }
+ }
+ return self;
+ },
+
+ /** @id MochiKit.Base.setdefault */
+ setdefault: function (self, obj/*, ...*/) {
+ if (self === null || self === undefined) {
+ self = {};
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var o = arguments[i];
+ for (var k in o) {
+ if (!(k in self)) {
+ self[k] = o[k];
+ }
+ }
+ }
+ return self;
+ },
+
+ /** @id MochiKit.Base.keys */
+ keys: function (obj) {
+ var rval = [];
+ for (var prop in obj) {
+ rval.push(prop);
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Base.values */
+ values: function (obj) {
+ var rval = [];
+ for (var prop in obj) {
+ rval.push(obj[prop]);
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Base.items */
+ items: function (obj) {
+ var rval = [];
+ var e;
+ for (var prop in obj) {
+ var v;
+ try {
+ v = obj[prop];
+ } catch (e) {
+ continue;
+ }
+ rval.push([prop, v]);
+ }
+ return rval;
+ },
+
+
+ _newNamedError: function (module, name, func) {
+ func.prototype = new MochiKit.Base.NamedError(module.NAME + "." + name);
+ func.prototype.constructor = func;
+ module[name] = func;
+ },
+
+
+ /** @id MochiKit.Base.operator */
+ operator: {
+ // unary logic operators
+ /** @id MochiKit.Base.truth */
+ truth: function (a) { return !!a; },
+ /** @id MochiKit.Base.lognot */
+ lognot: function (a) { return !a; },
+ /** @id MochiKit.Base.identity */
+ identity: function (a) { return a; },
+
+ // bitwise unary operators
+ /** @id MochiKit.Base.not */
+ not: function (a) { return ~a; },
+ /** @id MochiKit.Base.neg */
+ neg: function (a) { return -a; },
+
+ // binary operators
+ /** @id MochiKit.Base.add */
+ add: function (a, b) { return a + b; },
+ /** @id MochiKit.Base.sub */
+ sub: function (a, b) { return a - b; },
+ /** @id MochiKit.Base.div */
+ div: function (a, b) { return a / b; },
+ /** @id MochiKit.Base.mod */
+ mod: function (a, b) { return a % b; },
+ /** @id MochiKit.Base.mul */
+ mul: function (a, b) { return a * b; },
+
+ // bitwise binary operators
+ /** @id MochiKit.Base.and */
+ and: function (a, b) { return a & b; },
+ /** @id MochiKit.Base.or */
+ or: function (a, b) { return a | b; },
+ /** @id MochiKit.Base.xor */
+ xor: function (a, b) { return a ^ b; },
+ /** @id MochiKit.Base.lshift */
+ lshift: function (a, b) { return a << b; },
+ /** @id MochiKit.Base.rshift */
+ rshift: function (a, b) { return a >> b; },
+ /** @id MochiKit.Base.zrshift */
+ zrshift: function (a, b) { return a >>> b; },
+
+ // near-worthless built-in comparators
+ /** @id MochiKit.Base.eq */
+ eq: function (a, b) { return a == b; },
+ /** @id MochiKit.Base.ne */
+ ne: function (a, b) { return a != b; },
+ /** @id MochiKit.Base.gt */
+ gt: function (a, b) { return a > b; },
+ /** @id MochiKit.Base.ge */
+ ge: function (a, b) { return a >= b; },
+ /** @id MochiKit.Base.lt */
+ lt: function (a, b) { return a < b; },
+ /** @id MochiKit.Base.le */
+ le: function (a, b) { return a <= b; },
+
+ // strict built-in comparators
+ seq: function (a, b) { return a === b; },
+ sne: function (a, b) { return a !== b; },
+
+ // compare comparators
+ /** @id MochiKit.Base.ceq */
+ ceq: function (a, b) { return MochiKit.Base.compare(a, b) === 0; },
+ /** @id MochiKit.Base.cne */
+ cne: function (a, b) { return MochiKit.Base.compare(a, b) !== 0; },
+ /** @id MochiKit.Base.cgt */
+ cgt: function (a, b) { return MochiKit.Base.compare(a, b) == 1; },
+ /** @id MochiKit.Base.cge */
+ cge: function (a, b) { return MochiKit.Base.compare(a, b) != -1; },
+ /** @id MochiKit.Base.clt */
+ clt: function (a, b) { return MochiKit.Base.compare(a, b) == -1; },
+ /** @id MochiKit.Base.cle */
+ cle: function (a, b) { return MochiKit.Base.compare(a, b) != 1; },
+
+ // binary logical operators
+ /** @id MochiKit.Base.logand */
+ logand: function (a, b) { return a && b; },
+ /** @id MochiKit.Base.logor */
+ logor: function (a, b) { return a || b; },
+ /** @id MochiKit.Base.contains */
+ contains: function (a, b) { return b in a; }
+ },
+
+ /** @id MochiKit.Base.forwardCall */
+ forwardCall: function (func) {
+ return function () {
+ return this[func].apply(this, arguments);
+ };
+ },
+
+ /** @id MochiKit.Base.itemgetter */
+ itemgetter: function (func) {
+ return function (arg) {
+ return arg[func];
+ };
+ },
+
+ /** @id MochiKit.Base.bool */
+ bool: function (value) {
+ if (typeof(value) === "boolean" || value instanceof Boolean) {
+ return value.valueOf();
+ } else if (typeof(value) === "string" || value instanceof String) {
+ return value.length > 0 && value != "false" && value != "null" &&
+ value != "undefined" && value != "0";
+ } else if (typeof(value) === "number" || value instanceof Number) {
+ return !isNaN(value) && value != 0;
+ } else if (value != null && typeof(value.length) === "number") {
+ return value.length !== 0;
+ } else {
+ return value != null;
+ }
+ },
+
+ /** @id MochiKit.Base.typeMatcher */
+ typeMatcher: function (/* typ */) {
+ var types = {};
+ for (var i = 0; i < arguments.length; i++) {
+ var typ = arguments[i];
+ types[typ] = typ;
+ }
+ return function () {
+ for (var i = 0; i < arguments.length; i++) {
+ if (!(typeof(arguments[i]) in types)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ },
+
+ /** @id MochiKit.Base.isNull */
+ isNull: function (/* ... */) {
+ for (var i = 0; i < arguments.length; i++) {
+ if (arguments[i] !== null) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /** @id MochiKit.Base.isUndefinedOrNull */
+ isUndefinedOrNull: function (/* ... */) {
+ for (var i = 0; i < arguments.length; i++) {
+ var o = arguments[i];
+ if (!(typeof(o) == 'undefined' || o === null)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /** @id MochiKit.Base.isEmpty */
+ isEmpty: function (obj) {
+ return !MochiKit.Base.isNotEmpty.apply(this, arguments);
+ },
+
+ /** @id MochiKit.Base.isNotEmpty */
+ isNotEmpty: function (obj) {
+ for (var i = 0; i < arguments.length; i++) {
+ var o = arguments[i];
+ if (!(o && o.length)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /** @id MochiKit.Base.isArrayLike */
+ isArrayLike: function () {
+ for (var i = 0; i < arguments.length; i++) {
+ var o = arguments[i];
+ var typ = typeof(o);
+ if (
+ (typ != 'object' && !(typ == 'function' && typeof(o.item) == 'function')) ||
+ o === null ||
+ typeof(o.length) != 'number' ||
+ o.nodeType === 3 ||
+ o.nodeType === 4
+ ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /** @id MochiKit.Base.isDateLike */
+ isDateLike: function () {
+ for (var i = 0; i < arguments.length; i++) {
+ var o = arguments[i];
+ if (typeof(o) != "object" || o === null
+ || typeof(o.getTime) != 'function') {
+ return false;
+ }
+ }
+ return true;
+ },
+
+
+ /** @id MochiKit.Base.xmap */
+ xmap: function (fn/*, obj... */) {
+ if (fn === null) {
+ return MochiKit.Base.extend(null, arguments, 1);
+ }
+ var rval = [];
+ for (var i = 1; i < arguments.length; i++) {
+ rval.push(fn(arguments[i]));
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Base.map */
+ map: function (fn, lst/*, lst... */) {
+ var m = MochiKit.Base;
+ var itr = MochiKit.Iter;
+ var isArrayLike = m.isArrayLike;
+ if (arguments.length <= 2) {
+ // allow an iterable to be passed
+ if (!isArrayLike(lst)) {
+ if (itr) {
+ // fast path for map(null, iterable)
+ lst = itr.list(lst);
+ if (fn === null) {
+ return lst;
+ }
+ } else {
+ throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+ }
+ }
+ // fast path for map(null, lst)
+ if (fn === null) {
+ return m.extend(null, lst);
+ }
+ // disabled fast path for map(fn, lst)
+ /*
+ if (false && typeof(Array.prototype.map) == 'function') {
+ // Mozilla fast-path
+ return Array.prototype.map.call(lst, fn);
+ }
+ */
+ var rval = [];
+ for (var i = 0; i < lst.length; i++) {
+ rval.push(fn(lst[i]));
+ }
+ return rval;
+ } else {
+ // default for map(null, ...) is zip(...)
+ if (fn === null) {
+ fn = Array;
+ }
+ var length = null;
+ for (var i = 1; i < arguments.length; i++) {
+ // allow iterables to be passed
+ if (!isArrayLike(arguments[i])) {
+ if (itr) {
+ return itr.list(itr.imap.apply(null, arguments));
+ } else {
+ throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+ }
+ }
+ // find the minimum length
+ var l = arguments[i].length;
+ if (length === null || length > l) {
+ length = l;
+ }
+ }
+ rval = [];
+ for (var i = 0; i < length; i++) {
+ var args = [];
+ for (var j = 1; j < arguments.length; j++) {
+ args.push(arguments[j][i]);
+ }
+ rval.push(fn.apply(this, args));
+ }
+ return rval;
+ }
+ },
+
+ /** @id MochiKit.Base.xfilter */
+ xfilter: function (fn/*, obj... */) {
+ var rval = [];
+ if (fn === null) {
+ fn = MochiKit.Base.operator.truth;
+ }
+ for (var i = 1; i < arguments.length; i++) {
+ var o = arguments[i];
+ if (fn(o)) {
+ rval.push(o);
+ }
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Base.filter */
+ filter: function (fn, lst, self) {
+ var rval = [];
+ // allow an iterable to be passed
+ var m = MochiKit.Base;
+ if (!m.isArrayLike(lst)) {
+ if (MochiKit.Iter) {
+ lst = MochiKit.Iter.list(lst);
+ } else {
+ throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
+ }
+ }
+ if (fn === null) {
+ fn = m.operator.truth;
+ }
+ if (typeof(Array.prototype.filter) == 'function') {
+ // Mozilla fast-path
+ return Array.prototype.filter.call(lst, fn, self);
+ } else if (typeof(self) == 'undefined' || self === null) {
+ for (var i = 0; i < lst.length; i++) {
+ var o = lst[i];
+ if (fn(o)) {
+ rval.push(o);
+ }
+ }
+ } else {
+ for (var i = 0; i < lst.length; i++) {
+ o = lst[i];
+ if (fn.call(self, o)) {
+ rval.push(o);
+ }
+ }
+ }
+ return rval;
+ },
+
+
+ _wrapDumbFunction: function (func) {
+ return function () {
+ // fast path!
+ switch (arguments.length) {
+ case 0: return func();
+ case 1: return func(arguments[0]);
+ case 2: return func(arguments[0], arguments[1]);
+ case 3: return func(arguments[0], arguments[1], arguments[2]);
+ }
+ var args = [];
+ for (var i = 0; i < arguments.length; i++) {
+ args.push("arguments[" + i + "]");
+ }
+ return eval("(func(" + args.join(",") + "))");
+ };
+ },
+
+ /** @id MochiKit.Base.methodcaller */
+ methodcaller: function (func/*, args... */) {
+ var args = MochiKit.Base.extend(null, arguments, 1);
+ if (typeof(func) == "function") {
+ return function (obj) {
+ return func.apply(obj, args);
+ };
+ } else {
+ return function (obj) {
+ return obj[func].apply(obj, args);
+ };
+ }
+ },
+
+ /** @id MochiKit.Base.method */
+ method: function (self, func) {
+ var m = MochiKit.Base;
+ return m.bind.apply(this, m.extend([func, self], arguments, 2));
+ },
+
+ /** @id MochiKit.Base.compose */
+ compose: function (f1, f2/*, f3, ... fN */) {
+ var fnlist = [];
+ var m = MochiKit.Base;
+ if (arguments.length === 0) {
+ throw new TypeError("compose() requires at least one argument");
+ }
+ for (var i = 0; i < arguments.length; i++) {
+ var fn = arguments[i];
+ if (typeof(fn) != "function") {
+ throw new TypeError(m.repr(fn) + " is not a function");
+ }
+ fnlist.push(fn);
+ }
+ return function () {
+ var args = arguments;
+ for (var i = fnlist.length - 1; i >= 0; i--) {
+ args = [fnlist[i].apply(this, args)];
+ }
+ return args[0];
+ };
+ },
+
+ /** @id MochiKit.Base.bind */
+ bind: function (func, self/* args... */) {
+ if (typeof(func) == "string") {
+ func = self[func];
+ }
+ var im_func = func.im_func;
+ var im_preargs = func.im_preargs;
+ var im_self = func.im_self;
+ var m = MochiKit.Base;
+ if (typeof(func) == "function" && typeof(func.apply) == "undefined") {
+ // this is for cases where JavaScript sucks ass and gives you a
+ // really dumb built-in function like alert() that doesn't have
+ // an apply
+ func = m._wrapDumbFunction(func);
+ }
+ if (typeof(im_func) != 'function') {
+ im_func = func;
+ }
+ if (typeof(self) != 'undefined') {
+ im_self = self;
+ }
+ if (typeof(im_preargs) == 'undefined') {
+ im_preargs = [];
+ } else {
+ im_preargs = im_preargs.slice();
+ }
+ m.extend(im_preargs, arguments, 2);
+ var newfunc = function () {
+ var args = arguments;
+ var me = arguments.callee;
+ if (me.im_preargs.length > 0) {
+ args = m.concat(me.im_preargs, args);
+ }
+ var self = me.im_self;
+ if (!self) {
+ self = this;
+ }
+ return me.im_func.apply(self, args);
+ };
+ newfunc.im_self = im_self;
+ newfunc.im_func = im_func;
+ newfunc.im_preargs = im_preargs;
+ if (typeof(im_func.NAME) == 'string') {
+ newfunc.NAME = "bind(" + im_func.NAME + ",...)";
+ }
+ return newfunc;
+ },
+
+ /** @id MochiKit.Base.bindLate */
+ bindLate: function (func, self/* args... */) {
+ var m = MochiKit.Base;
+ var args = arguments;
+ if (typeof(func) === "string") {
+ args = m.extend([m.forwardCall(func)], arguments, 1);
+ return m.bind.apply(this, args);
+ }
+ return m.bind.apply(this, args);
+ },
+
+ /** @id MochiKit.Base.bindMethods */
+ bindMethods: function (self) {
+ var bind = MochiKit.Base.bind;
+ for (var k in self) {
+ var func = self[k];
+ if (typeof(func) == 'function') {
+ self[k] = bind(func, self);
+ }
+ }
+ },
+
+ /** @id MochiKit.Base.registerComparator */
+ registerComparator: function (name, check, comparator, /* optional */ override) {
+ MochiKit.Base.comparatorRegistry.register(name, check, comparator, override);
+ },
+
+ _primitives: {'boolean': true, 'string': true, 'number': true},
+
+ /** @id MochiKit.Base.compare */
+ compare: function (a, b) {
+ if (a == b) {
+ return 0;
+ }
+ var aIsNull = (typeof(a) == 'undefined' || a === null);
+ var bIsNull = (typeof(b) == 'undefined' || b === null);
+ if (aIsNull && bIsNull) {
+ return 0;
+ } else if (aIsNull) {
+ return -1;
+ } else if (bIsNull) {
+ return 1;
+ }
+ var m = MochiKit.Base;
+ // bool, number, string have meaningful comparisons
+ var prim = m._primitives;
+ if (!(typeof(a) in prim && typeof(b) in prim)) {
+ try {
+ return m.comparatorRegistry.match(a, b);
+ } catch (e) {
+ if (e != m.NotFound) {
+ throw e;
+ }
+ }
+ }
+ if (a < b) {
+ return -1;
+ } else if (a > b) {
+ return 1;
+ }
+ // These types can't be compared
+ var repr = m.repr;
+ throw new TypeError(repr(a) + " and " + repr(b) + " can not be compared");
+ },
+
+ /** @id MochiKit.Base.compareDateLike */
+ compareDateLike: function (a, b) {
+ return MochiKit.Base.compare(a.getTime(), b.getTime());
+ },
+
+ /** @id MochiKit.Base.compareArrayLike */
+ compareArrayLike: function (a, b) {
+ var compare = MochiKit.Base.compare;
+ var count = a.length;
+ var rval = 0;
+ if (count > b.length) {
+ rval = 1;
+ count = b.length;
+ } else if (count < b.length) {
+ rval = -1;
+ }
+ for (var i = 0; i < count; i++) {
+ var cmp = compare(a[i], b[i]);
+ if (cmp) {
+ return cmp;
+ }
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Base.registerRepr */
+ registerRepr: function (name, check, wrap, /* optional */override) {
+ MochiKit.Base.reprRegistry.register(name, check, wrap, override);
+ },
+
+ /** @id MochiKit.Base.repr */
+ repr: function (o) {
+ if (typeof(o) == "undefined") {
+ return "undefined";
+ } else if (o === null) {
+ return "null";
+ }
+ try {
+ if (typeof(o.__repr__) == 'function') {
+ return o.__repr__();
+ } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) {
+ return o.repr();
+ }
+ return MochiKit.Base.reprRegistry.match(o);
+ } catch (e) {
+ try {
+ if (typeof(o.NAME) == 'string' && (
+ o.toString == Function.prototype.toString ||
+ o.toString == Object.prototype.toString
+ )) {
+ return o.NAME;
+ }
+ } catch (ignore) {
+ }
+ }
+ try {
+ var ostring = (o + "");
+ } catch (e) {
+ return "[" + typeof(o) + "]";
+ }
+ if (typeof(o) == "function") {
+ ostring = ostring.replace(/^\s+/, "").replace(/\s+/g, " ");
+ ostring = ostring.replace(/,(\S)/, ", $1");
+ var idx = ostring.indexOf("{");
+ if (idx != -1) {
+ ostring = ostring.substr(0, idx) + "{...}";
+ }
+ }
+ return ostring;
+ },
+
+ /** @id MochiKit.Base.reprArrayLike */
+ reprArrayLike: function (o) {
+ var m = MochiKit.Base;
+ return "[" + m.map(m.repr, o).join(", ") + "]";
+ },
+
+ /** @id MochiKit.Base.reprString */
+ reprString: function (o) {
+ return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
+ ).replace(/[\f]/g, "\\f"
+ ).replace(/[\b]/g, "\\b"
+ ).replace(/[\n]/g, "\\n"
+ ).replace(/[\t]/g, "\\t"
+ ).replace(/[\v]/g, "\\v"
+ ).replace(/[\r]/g, "\\r");
+ },
+
+ /** @id MochiKit.Base.reprNumber */
+ reprNumber: function (o) {
+ return o + "";
+ },
+
+ /** @id MochiKit.Base.registerJSON */
+ registerJSON: function (name, check, wrap, /* optional */override) {
+ MochiKit.Base.jsonRegistry.register(name, check, wrap, override);
+ },
+
+
+ /** @id MochiKit.Base.evalJSON */
+ evalJSON: function (jsonText) {
+ return eval("(" + MochiKit.Base._filterJSON(jsonText) + ")");
+ },
+
+ _filterJSON: function (s) {
+ var m = s.match(/^\s*\/\*(.*)\*\/\s*$/);
+ return (m) ? m[1] : s;
+ },
+
+ /** @id MochiKit.Base.serializeJSON */
+ serializeJSON: function (o) {
+ var objtype = typeof(o);
+ if (objtype == "number" || objtype == "boolean") {
+ return o + "";
+ } else if (o === null) {
+ return "null";
+ } else if (objtype == "string") {
+ var res = "";
+ for (var i = 0; i < o.length; i++) {
+ var c = o.charAt(i);
+ if (c == '\"') {
+ res += '\\"';
+ } else if (c == '\\') {
+ res += '\\\\';
+ } else if (c == '\b') {
+ res += '\\b';
+ } else if (c == '\f') {
+ res += '\\f';
+ } else if (c == '\n') {
+ res += '\\n';
+ } else if (c == '\r') {
+ res += '\\r';
+ } else if (c == '\t') {
+ res += '\\t';
+ } else if (o.charCodeAt(i) <= 0x1F) {
+ var hex = o.charCodeAt(i).toString(16);
+ if (hex.length < 2) {
+ hex = '0' + hex;
+ }
+ res += '\\u00' + hex.toUpperCase();
+ } else {
+ res += c;
+ }
+ }
+ return '"' + res + '"';
+ }
+ // recurse
+ var me = arguments.callee;
+ // short-circuit for objects that support "json" serialization
+ // if they return "self" then just pass-through...
+ var newObj;
+ if (typeof(o.toJSON) == "function") {
+ newObj = o.toJSON();
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ }
+ if (typeof(o.__json__) == "function") {
+ newObj = o.__json__();
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ }
+ if (typeof(o.json) == "function") {
+ newObj = o.json();
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ }
+ // array
+ if (objtype != "function" && typeof(o.length) == "number") {
+ var res = [];
+ for (var i = 0; i < o.length; i++) {
+ var val = me(o[i]);
+ if (typeof(val) != "string") {
+ // skip non-serializable values
+ continue;
+ }
+ res.push(val);
+ }
+ return "[" + res.join(", ") + "]";
+ }
+ // look in the registry
+ var m = MochiKit.Base;
+ try {
+ newObj = m.jsonRegistry.match(o);
+ if (o !== newObj) {
+ return me(newObj);
+ }
+ } catch (e) {
+ if (e != m.NotFound) {
+ // something really bad happened
+ throw e;
+ }
+ }
+ // undefined is outside of the spec
+ if (objtype == "undefined") {
+ throw new TypeError("undefined can not be serialized as JSON");
+ }
+ // it's a function with no adapter, bad
+ if (objtype == "function") {
+ return null;
+ }
+ // generic object code path
+ res = [];
+ for (var k in o) {
+ var useKey;
+ if (typeof(k) == "number") {
+ useKey = '"' + k + '"';
+ } else if (typeof(k) == "string") {
+ useKey = me(k);
+ } else {
+ // skip non-string or number keys
+ continue;
+ }
+ val = me(o[k]);
+ if (typeof(val) != "string") {
+ // skip non-serializable values
+ continue;
+ }
+ res.push(useKey + ":" + val);
+ }
+ return "{" + res.join(", ") + "}";
+ },
+
+
+ /** @id MochiKit.Base.objEqual */
+ objEqual: function (a, b) {
+ return (MochiKit.Base.compare(a, b) === 0);
+ },
+
+ /** @id MochiKit.Base.arrayEqual */
+ arrayEqual: function (self, arr) {
+ if (self.length != arr.length) {
+ return false;
+ }
+ return (MochiKit.Base.compare(self, arr) === 0);
+ },
+
+ /** @id MochiKit.Base.concat */
+ concat: function (/* lst... */) {
+ var rval = [];
+ var extend = MochiKit.Base.extend;
+ for (var i = 0; i < arguments.length; i++) {
+ extend(rval, arguments[i]);
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Base.keyComparator */
+ keyComparator: function (key/* ... */) {
+ // fast-path for single key comparisons
+ var m = MochiKit.Base;
+ var compare = m.compare;
+ if (arguments.length == 1) {
+ return function (a, b) {
+ return compare(a[key], b[key]);
+ };
+ }
+ var compareKeys = m.extend(null, arguments);
+ return function (a, b) {
+ var rval = 0;
+ // keep comparing until something is inequal or we run out of
+ // keys to compare
+ for (var i = 0; (rval === 0) && (i < compareKeys.length); i++) {
+ var key = compareKeys[i];
+ rval = compare(a[key], b[key]);
+ }
+ return rval;
+ };
+ },
+
+ /** @id MochiKit.Base.reverseKeyComparator */
+ reverseKeyComparator: function (key) {
+ var comparator = MochiKit.Base.keyComparator.apply(this, arguments);
+ return function (a, b) {
+ return comparator(b, a);
+ };
+ },
+
+ /** @id MochiKit.Base.partial */
+ partial: function (func) {
+ var m = MochiKit.Base;
+ return m.bind.apply(this, m.extend([func, undefined], arguments, 1));
+ },
+
+ /** @id MochiKit.Base.listMinMax */
+ listMinMax: function (which, lst) {
+ if (lst.length === 0) {
+ return null;
+ }
+ var cur = lst[0];
+ var compare = MochiKit.Base.compare;
+ for (var i = 1; i < lst.length; i++) {
+ var o = lst[i];
+ if (compare(o, cur) == which) {
+ cur = o;
+ }
+ }
+ return cur;
+ },
+
+ /** @id MochiKit.Base.objMax */
+ objMax: function (/* obj... */) {
+ return MochiKit.Base.listMinMax(1, arguments);
+ },
+
+ /** @id MochiKit.Base.objMin */
+ objMin: function (/* obj... */) {
+ return MochiKit.Base.listMinMax(-1, arguments);
+ },
+
+ /** @id MochiKit.Base.findIdentical */
+ findIdentical: function (lst, value, start/* = 0 */, /* optional */end) {
+ if (typeof(end) == "undefined" || end === null) {
+ end = lst.length;
+ }
+ if (typeof(start) == "undefined" || start === null) {
+ start = 0;
+ }
+ for (var i = start; i < end; i++) {
+ if (lst[i] === value) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ /** @id MochiKit.Base.mean */
+ mean: function(/* lst... */) {
+ /* http://www.nist.gov/dads/HTML/mean.html */
+ var sum = 0;
+
+ var m = MochiKit.Base;
+ var args = m.extend(null, arguments);
+ var count = args.length;
+
+ while (args.length) {
+ var o = args.shift();
+ if (o && typeof(o) == "object" && typeof(o.length) == "number") {
+ count += o.length - 1;
+ for (var i = o.length - 1; i >= 0; i--) {
+ sum += o[i];
+ }
+ } else {
+ sum += o;
+ }
+ }
+
+ if (count <= 0) {
+ throw new TypeError('mean() requires at least one argument');
+ }
+
+ return sum/count;
+ },
+
+ /** @id MochiKit.Base.median */
+ median: function(/* lst... */) {
+ /* http://www.nist.gov/dads/HTML/median.html */
+ var data = MochiKit.Base.flattenArguments(arguments);
+ if (data.length === 0) {
+ throw new TypeError('median() requires at least one argument');
+ }
+ data.sort(MochiKit.Base.compare);
+ if (data.length % 2 == 0) {
+ var upper = data.length / 2;
+ return (data[upper] + data[upper - 1]) / 2;
+ } else {
+ return data[(data.length - 1) / 2];
+ }
+ },
+
+ /** @id MochiKit.Base.findValue */
+ findValue: function (lst, value, start/* = 0 */, /* optional */end) {
+ if (typeof(end) == "undefined" || end === null) {
+ end = lst.length;
+ }
+ if (typeof(start) == "undefined" || start === null) {
+ start = 0;
+ }
+ var cmp = MochiKit.Base.compare;
+ for (var i = start; i < end; i++) {
+ if (cmp(lst[i], value) === 0) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ /** @id MochiKit.Base.nodeWalk */
+ nodeWalk: function (node, visitor) {
+ var nodes = [node];
+ var extend = MochiKit.Base.extend;
+ while (nodes.length) {
+ var res = visitor(nodes.shift());
+ if (res) {
+ extend(nodes, res);
+ }
+ }
+ },
+
+
+ /** @id MochiKit.Base.nameFunctions */
+ nameFunctions: function (namespace) {
+ var base = namespace.NAME;
+ if (typeof(base) == 'undefined') {
+ base = '';
+ } else {
+ base = base + '.';
+ }
+ for (var name in namespace) {
+ var o = namespace[name];
+ if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
+ try {
+ o.NAME = base + name;
+ } catch (e) {
+ // pass
+ }
+ }
+ }
+ },
+
+
+ /** @id MochiKit.Base.queryString */
+ queryString: function (names, values) {
+ // check to see if names is a string or a DOM element, and if
+ // MochiKit.DOM is available. If so, drop it like it's a form
+ // Ugliest conditional in MochiKit? Probably!
+ if (typeof(MochiKit.DOM) != "undefined" && arguments.length == 1
+ && (typeof(names) == "string" || (
+ typeof(names.nodeType) != "undefined" && names.nodeType > 0
+ ))
+ ) {
+ var kv = MochiKit.DOM.formContents(names);
+ names = kv[0];
+ values = kv[1];
+ } else if (arguments.length == 1) {
+ // Allow the return value of formContents to be passed directly
+ if (typeof(names.length) == "number" && names.length == 2) {
+ return arguments.callee(names[0], names[1]);
+ }
+ var o = names;
+ names = [];
+ values = [];
+ for (var k in o) {
+ var v = o[k];
+ if (typeof(v) == "function") {
+ continue;
+ } else if (MochiKit.Base.isArrayLike(v)){
+ for (var i = 0; i < v.length; i++) {
+ names.push(k);
+ values.push(v[i]);
+ }
+ } else {
+ names.push(k);
+ values.push(v);
+ }
+ }
+ }
+ var rval = [];
+ var len = Math.min(names.length, values.length);
+ var urlEncode = MochiKit.Base.urlEncode;
+ for (var i = 0; i < len; i++) {
+ v = values[i];
+ if (typeof(v) != 'undefined' && v !== null) {
+ rval.push(urlEncode(names[i]) + "=" + urlEncode(v));
+ }
+ }
+ return rval.join("&");
+ },
+
+
+ /** @id MochiKit.Base.parseQueryString */
+ parseQueryString: function (encodedString, useArrays) {
+ // strip a leading '?' from the encoded string
+ var qstr = (encodedString.charAt(0) == "?")
+ ? encodedString.substring(1)
+ : encodedString;
+ var pairs = qstr.replace(/\+/g, "%20").split(/\&\;|\&\#38\;|\&|\&/);
+ var o = {};
+ var decode;
+ if (typeof(decodeURIComponent) != "undefined") {
+ decode = decodeURIComponent;
+ } else {
+ decode = unescape;
+ }
+ if (useArrays) {
+ for (var i = 0; i < pairs.length; i++) {
+ var pair = pairs[i].split("=");
+ var name = decode(pair.shift());
+ if (!name) {
+ continue;
+ }
+ var arr = o[name];
+ if (!(arr instanceof Array)) {
+ arr = [];
+ o[name] = arr;
+ }
+ arr.push(decode(pair.join("=")));
+ }
+ } else {
+ for (var i = 0; i < pairs.length; i++) {
+ pair = pairs[i].split("=");
+ var name = pair.shift();
+ if (!name) {
+ continue;
+ }
+ o[decode(name)] = decode(pair.join("="));
+ }
+ }
+ return o;
+ }
+});
+
+/** @id MochiKit.Base.AdapterRegistry */
+MochiKit.Base.AdapterRegistry = function () {
+ this.pairs = [];
+};
+
+MochiKit.Base.AdapterRegistry.prototype = {
+ /** @id MochiKit.Base.AdapterRegistry.prototype.register */
+ register: function (name, check, wrap, /* optional */ override) {
+ if (override) {
+ this.pairs.unshift([name, check, wrap]);
+ } else {
+ this.pairs.push([name, check, wrap]);
+ }
+ },
+
+ /** @id MochiKit.Base.AdapterRegistry.prototype.match */
+ match: function (/* ... */) {
+ for (var i = 0; i < this.pairs.length; i++) {
+ var pair = this.pairs[i];
+ if (pair[1].apply(this, arguments)) {
+ return pair[2].apply(this, arguments);
+ }
+ }
+ throw MochiKit.Base.NotFound;
+ },
+
+ /** @id MochiKit.Base.AdapterRegistry.prototype.unregister */
+ unregister: function (name) {
+ for (var i = 0; i < this.pairs.length; i++) {
+ var pair = this.pairs[i];
+ if (pair[0] == name) {
+ this.pairs.splice(i, 1);
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+/**
+ * Exports all symbols from one or more modules into the specified
+ * namespace (or scope). This is similar to MochiKit.Base.update(),
+ * except for special handling of the "__export__" flag, contained
+ * sub-modules (exported recursively), and names starting with "_".
+ *
+ * @param {Object} namespace the object or scope to modify
+ * @param {Object} module the module to export
+ */
+MochiKit.Base.moduleExport = function (namespace, module/*, ...*/) {
+ var SKIP = { toString: true, NAME: true, VERSION: true };
+ var mods = MochiKit.Base.extend([], arguments, 1);
+ while ((module = mods.shift()) != null) {
+ for (var k in module) {
+ var v = module[k];
+ if (v != null) {
+ var flagSet = (typeof(v.__export__) == 'boolean');
+ var nameValid = (k[0] !== "_" && !SKIP[k]);
+ if (flagSet ? v.__export__ : nameValid) {
+ if (typeof(v) == 'object' && v.NAME && v.VERSION) {
+ mods.push(v);
+ } else {
+ namespace[k] = module[k];
+ }
+ }
+ }
+ }
+ }
+ return namespace;
+};
+
+/**
+ * Identical to moduleExport, but also considers the global and
+ * module-specific "__export__" flag.
+ */
+MochiKit.Base._exportSymbols = function (namespace, module) {
+ if (MochiKit.__export__ !== false && module.__export__ !== false) {
+ MochiKit.Base.moduleExport(namespace, module);
+ }
+};
+
+/**
+ * Creates a deprecated function alias in the specified module. The
+ * deprecated function will forward all calls and arguments to a
+ * target function, while also logging a debug message on the first
+ * call (if MochiKit.Logging is loaded). The destination function may
+ * be located in another module, which must be loaded, or an
+ * exception will be thrown.
+ *
+ * @param {Object/String} module the source module or module name
+ * (e.g. 'DOM' or 'MochiKit.DOM')
+ * @param {String} name the deprecated function name (e.g. 'getStyle')
+ * @param {String} target the fully qualified name of the target
+ * function (e.g. 'MochiKit.Style.getStyle')
+ * @param {String} version the first version when the source function
+ * was deprecated (e.g. '1.4')
+ * @param {Boolean} [exportable] the exportable function flag,
+ * defaults to false
+ */
+MochiKit.Base._deprecated = function (module, name, target, version, exportable) {
+ if (typeof(module) === 'string') {
+ if (module.indexOf('MochiKit.') === 0) {
+ module = module.substring(9);
+ }
+ module = MochiKit[module];
+ }
+ var targetModule = target.split('.')[1];
+ var targetName = target.split('.')[2];
+ var func = function () {
+ var self = arguments.callee;
+ var msg = module.NAME + '.' + name + ' is deprecated since version ' +
+ version + '. Use ' + target + ' instead.';
+ if (self.logged !== true) {
+ self.logged = true;
+ if (MochiKit.Logging) {
+ MochiKit.Logging.logDebug(msg);
+ } else if (console && console.log) {
+ console.log(msg);
+ }
+ }
+ if (!MochiKit[targetModule]) {
+ throw new Error(msg);
+ }
+ return MochiKit[targetModule][targetName].apply(this, arguments);
+ };
+ func.__export__ = (exportable === true);
+ module[name] = func;
+};
+
+MochiKit.Base.__new__ = function () {
+ var m = this;
+
+ /** @id MochiKit.Base.noop */
+ m.noop = m.operator.identity;
+
+ // Backwards compat
+ m._deprecated(m, 'forward', 'MochiKit.Base.forwardCall', '1.3');
+ m._deprecated(m, 'find', 'MochiKit.Base.findValue', '1.3');
+
+ if (typeof(encodeURIComponent) != "undefined") {
+ /** @id MochiKit.Base.urlEncode */
+ m.urlEncode = function (unencoded) {
+ return encodeURIComponent(unencoded).replace(/\'/g, '%27');
+ };
+ } else {
+ m.urlEncode = function (unencoded) {
+ return escape(unencoded
+ ).replace(/\+/g, '%2B'
+ ).replace(/\"/g,'%22'
+ ).replace(/\'/g, '%27');
+ };
+ }
+
+ /** @id MochiKit.Base.NamedError */
+ m.NamedError = function (name) {
+ this.message = name;
+ this.name = name;
+ };
+ m.NamedError.prototype = new Error();
+ m.NamedError.prototype.constructor = m.NamedError;
+ m.update(m.NamedError.prototype, {
+ repr: function () {
+ if (this.message && this.message != this.name) {
+ return this.name + "(" + m.repr(this.message) + ")";
+ } else {
+ return this.name + "()";
+ }
+ },
+ toString: m.forwardCall("repr")
+ });
+
+ /** @id MochiKit.Base.NotFound */
+ m.NotFound = new m.NamedError("MochiKit.Base.NotFound");
+
+
+ /** @id MochiKit.Base.listMax */
+ m.listMax = m.partial(m.listMinMax, 1);
+ /** @id MochiKit.Base.listMin */
+ m.listMin = m.partial(m.listMinMax, -1);
+
+ /** @id MochiKit.Base.isCallable */
+ m.isCallable = m.typeMatcher('function');
+ /** @id MochiKit.Base.isUndefined */
+ m.isUndefined = m.typeMatcher('undefined');
+ /** @id MochiKit.Base.isValue */
+ m.isValue = m.typeMatcher('boolean', 'number', 'string');
+
+ /** @id MochiKit.Base.merge */
+ m.merge = m.partial(m.update, null);
+ /** @id MochiKit.Base.zip */
+ m.zip = m.partial(m.map, null);
+
+ /** @id MochiKit.Base.average */
+ m.average = m.mean;
+
+ /** @id MochiKit.Base.comparatorRegistry */
+ m.comparatorRegistry = new m.AdapterRegistry();
+ m.registerComparator("dateLike", m.isDateLike, m.compareDateLike);
+ m.registerComparator("arrayLike", m.isArrayLike, m.compareArrayLike);
+
+ /** @id MochiKit.Base.reprRegistry */
+ m.reprRegistry = new m.AdapterRegistry();
+ m.registerRepr("arrayLike", m.isArrayLike, m.reprArrayLike);
+ m.registerRepr("string", m.typeMatcher("string"), m.reprString);
+ m.registerRepr("numbers", m.typeMatcher("number", "boolean"), m.reprNumber);
+
+ /** @id MochiKit.Base.jsonRegistry */
+ m.jsonRegistry = new m.AdapterRegistry();
+
+ m.nameFunctions(this);
+
+};
+
+MochiKit.Base.__new__();
+
+//
+// XXX: Internet Explorer blows
+//
+if (MochiKit.__export__) {
+ compare = MochiKit.Base.compare;
+ compose = MochiKit.Base.compose;
+ serializeJSON = MochiKit.Base.serializeJSON;
+ mean = MochiKit.Base.mean;
+ median = MochiKit.Base.median;
+}
+
+MochiKit.Base._exportSymbols(this, MochiKit.Base);
diff --git a/frontend/delta/js/MochiKit/Color.js b/frontend/delta/js/MochiKit/Color.js
new file mode 100644
index 0000000..f421737
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Color.js
@@ -0,0 +1,846 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Color 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito and others. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Color', '1.5', ['Base', 'DOM', 'Style']);
+
+/** @id MochiKit.Color.Color */
+MochiKit.Color.Color = function (red, green, blue, alpha) {
+ if (typeof(alpha) == 'undefined' || alpha === null) {
+ alpha = 1.0;
+ }
+ this.rgb = {
+ r: red,
+ g: green,
+ b: blue,
+ a: alpha
+ };
+};
+
+
+// Prototype methods
+
+MochiKit.Color.Color.prototype = {
+
+ __class__: MochiKit.Color.Color,
+
+ /** @id MochiKit.Color.Color.prototype.colorWithAlpha */
+ colorWithAlpha: function (alpha) {
+ var rgb = this.rgb;
+ var m = MochiKit.Color;
+ return m.Color.fromRGB(rgb.r, rgb.g, rgb.b, alpha);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.colorWithHue */
+ colorWithHue: function (hue) {
+ // get an HSL model, and set the new hue...
+ var hsl = this.asHSL();
+ hsl.h = hue;
+ var m = MochiKit.Color;
+ // convert back to RGB...
+ return m.Color.fromHSL(hsl);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.colorWithSaturation */
+ colorWithSaturation: function (saturation) {
+ // get an HSL model, and set the new hue...
+ var hsl = this.asHSL();
+ hsl.s = saturation;
+ var m = MochiKit.Color;
+ // convert back to RGB...
+ return m.Color.fromHSL(hsl);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.colorWithLightness */
+ colorWithLightness: function (lightness) {
+ // get an HSL model, and set the new hue...
+ var hsl = this.asHSL();
+ hsl.l = lightness;
+ var m = MochiKit.Color;
+ // convert back to RGB...
+ return m.Color.fromHSL(hsl);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.darkerColorWithLevel */
+ darkerColorWithLevel: function (level) {
+ var hsl = this.asHSL();
+ hsl.l = Math.max(hsl.l - level, 0);
+ var m = MochiKit.Color;
+ return m.Color.fromHSL(hsl);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.lighterColorWithLevel */
+ lighterColorWithLevel: function (level) {
+ var hsl = this.asHSL();
+ hsl.l = Math.min(hsl.l + level, 1);
+ var m = MochiKit.Color;
+ return m.Color.fromHSL(hsl);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.blendedColor */
+ blendedColor: function (other, /* optional */ fraction) {
+ if (typeof(fraction) == 'undefined' || fraction === null) {
+ fraction = 0.5;
+ }
+ var sf = 1.0 - fraction;
+ var s = this.rgb;
+ var d = other.rgb;
+ var df = fraction;
+ return MochiKit.Color.Color.fromRGB(
+ (s.r * sf) + (d.r * df),
+ (s.g * sf) + (d.g * df),
+ (s.b * sf) + (d.b * df),
+ (s.a * sf) + (d.a * df)
+ );
+ },
+
+ /** @id MochiKit.Color.Color.prototype.compareRGB */
+ compareRGB: function (other) {
+ var a = this.asRGB();
+ var b = other.asRGB();
+ return MochiKit.Base.compare(
+ [a.r, a.g, a.b, a.a],
+ [b.r, b.g, b.b, b.a]
+ );
+ },
+
+ /** @id MochiKit.Color.Color.prototype.isLight */
+ isLight: function () {
+ return this.asHSL().l > 0.5;
+ },
+
+ /** @id MochiKit.Color.Color.prototype.isDark */
+ isDark: function () {
+ return (!this.isLight());
+ },
+
+ /** @id MochiKit.Color.Color.prototype.toHSLString */
+ toHSLString: function () {
+ var c = this.asHSL();
+ var ccc = MochiKit.Color.clampColorComponent;
+ var rval = this._hslString;
+ if (!rval) {
+ var mid = (
+ ccc(c.h, 360).toFixed(0)
+ + "," + ccc(c.s, 100).toPrecision(4) + "%"
+ + "," + ccc(c.l, 100).toPrecision(4) + "%"
+ );
+ var a = c.a;
+ if (a >= 1) {
+ a = 1;
+ rval = "hsl(" + mid + ")";
+ } else {
+ if (a <= 0) {
+ a = 0;
+ }
+ rval = "hsla(" + mid + "," + a + ")";
+ }
+ this._hslString = rval;
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Color.Color.prototype.toRGBString */
+ toRGBString: function () {
+ var c = this.rgb;
+ var ccc = MochiKit.Color.clampColorComponent;
+ var rval = this._rgbString;
+ if (!rval) {
+ var mid = (
+ ccc(c.r, 255).toFixed(0)
+ + "," + ccc(c.g, 255).toFixed(0)
+ + "," + ccc(c.b, 255).toFixed(0)
+ );
+ if (c.a != 1) {
+ rval = "rgba(" + mid + "," + c.a + ")";
+ } else {
+ rval = "rgb(" + mid + ")";
+ }
+ this._rgbString = rval;
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Color.Color.prototype.asRGB */
+ asRGB: function () {
+ return MochiKit.Base.clone(this.rgb);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.toHexString */
+ toHexString: function () {
+ var m = MochiKit.Color;
+ var c = this.rgb;
+ var ccc = MochiKit.Color.clampColorComponent;
+ var rval = this._hexString;
+ if (!rval) {
+ rval = ("#" +
+ m.toColorPart(ccc(c.r, 255)) +
+ m.toColorPart(ccc(c.g, 255)) +
+ m.toColorPart(ccc(c.b, 255))
+ );
+ this._hexString = rval;
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Color.Color.prototype.asHSV */
+ asHSV: function () {
+ var hsv = this.hsv;
+ var c = this.rgb;
+ if (typeof(hsv) == 'undefined' || hsv === null) {
+ hsv = MochiKit.Color.rgbToHSV(this.rgb);
+ this.hsv = hsv;
+ }
+ return MochiKit.Base.clone(hsv);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.asHSL */
+ asHSL: function () {
+ var hsl = this.hsl;
+ var c = this.rgb;
+ if (typeof(hsl) == 'undefined' || hsl === null) {
+ hsl = MochiKit.Color.rgbToHSL(this.rgb);
+ this.hsl = hsl;
+ }
+ return MochiKit.Base.clone(hsl);
+ },
+
+ /** @id MochiKit.Color.Color.prototype.toString */
+ toString: function () {
+ return this.toRGBString();
+ },
+
+ /** @id MochiKit.Color.Color.prototype.repr */
+ repr: function () {
+ var c = this.rgb;
+ var col = [c.r, c.g, c.b, c.a];
+ return this.__class__.NAME + "(" + col.join(", ") + ")";
+ }
+
+};
+
+// Constructor methods
+
+MochiKit.Base.update(MochiKit.Color.Color, {
+ /** @id MochiKit.Color.Color.fromRGB */
+ fromRGB: function (red, green, blue, alpha) {
+ // designated initializer
+ var Color = MochiKit.Color.Color;
+ if (arguments.length == 1) {
+ var rgb = red;
+ red = rgb.r;
+ green = rgb.g;
+ blue = rgb.b;
+ if (typeof(rgb.a) == 'undefined') {
+ alpha = undefined;
+ } else {
+ alpha = rgb.a;
+ }
+ }
+ return new Color(red, green, blue, alpha);
+ },
+
+ /** @id MochiKit.Color.Color.fromHSL */
+ fromHSL: function (hue, saturation, lightness, alpha) {
+ var m = MochiKit.Color;
+ return m.Color.fromRGB(m.hslToRGB.apply(m, arguments));
+ },
+
+ /** @id MochiKit.Color.Color.fromHSV */
+ fromHSV: function (hue, saturation, value, alpha) {
+ var m = MochiKit.Color;
+ return m.Color.fromRGB(m.hsvToRGB.apply(m, arguments));
+ },
+
+ /** @id MochiKit.Color.Color.fromName */
+ fromName: function (name) {
+ var Color = MochiKit.Color.Color;
+ // Opera 9 seems to "quote" named colors(?!)
+ if (name.charAt(0) == '"') {
+ name = name.substr(1, name.length - 2);
+ }
+ var htmlColor = Color._namedColors[name.toLowerCase()];
+ if (typeof(htmlColor) == 'string') {
+ return Color.fromHexString(htmlColor);
+ } else if (name == "transparent") {
+ return Color.transparentColor();
+ }
+ return null;
+ },
+
+ /** @id MochiKit.Color.Color.fromString */
+ fromString: function (colorString) {
+ var self = MochiKit.Color.Color;
+ var three = colorString.substr(0, 3);
+ if (three == "rgb") {
+ return self.fromRGBString(colorString);
+ } else if (three == "hsl") {
+ return self.fromHSLString(colorString);
+ } else if (colorString.charAt(0) == "#") {
+ return self.fromHexString(colorString);
+ }
+ return self.fromName(colorString);
+ },
+
+
+ /** @id MochiKit.Color.Color.fromHexString */
+ fromHexString: function (hexCode) {
+ if (hexCode.charAt(0) == '#') {
+ hexCode = hexCode.substring(1);
+ }
+ var components = [];
+ var i, hex;
+ if (hexCode.length == 3) {
+ for (i = 0; i < 3; i++) {
+ hex = hexCode.substr(i, 1);
+ components.push(parseInt(hex + hex, 16) / 255.0);
+ }
+ } else {
+ for (i = 0; i < 6; i += 2) {
+ hex = hexCode.substr(i, 2);
+ components.push(parseInt(hex, 16) / 255.0);
+ }
+ }
+ var Color = MochiKit.Color.Color;
+ return Color.fromRGB.apply(Color, components);
+ },
+
+
+ _fromColorString: function (pre, method, scales, colorCode) {
+ // parses either HSL or RGB
+ if (colorCode.indexOf(pre) === 0) {
+ colorCode = colorCode.substring(colorCode.indexOf("(", 3) + 1, colorCode.length - 1);
+ }
+ var colorChunks = colorCode.split(/\s*,\s*/);
+ var colorFloats = [];
+ for (var i = 0; i < colorChunks.length; i++) {
+ var c = colorChunks[i];
+ var val;
+ var three = c.substring(c.length - 3);
+ if (c.charAt(c.length - 1) == '%') {
+ val = 0.01 * parseFloat(c.substring(0, c.length - 1));
+ } else if (three == "deg") {
+ val = parseFloat(c) / 360.0;
+ } else if (three == "rad") {
+ val = parseFloat(c) / (Math.PI * 2);
+ } else {
+ val = scales[i] * parseFloat(c);
+ }
+ colorFloats.push(val);
+ }
+ return this[method].apply(this, colorFloats);
+ },
+
+ /** @id MochiKit.Color.Color.fromComputedStyle */
+ fromComputedStyle: function (elem, style) {
+ var d = MochiKit.DOM;
+ var cls = MochiKit.Color.Color;
+ for (elem = d.getElement(elem); elem; elem = elem.parentNode) {
+ var actualColor = MochiKit.Style.getStyle.apply(d, arguments);
+ if (!actualColor) {
+ continue;
+ }
+ var color = cls.fromString(actualColor);
+ if (!color) {
+ break;
+ }
+ if (color.asRGB().a > 0) {
+ return color;
+ }
+ }
+ return null;
+ },
+
+ /** @id MochiKit.Color.Color.fromBackground */
+ fromBackground: function (elem) {
+ var cls = MochiKit.Color.Color;
+ return cls.fromComputedStyle(
+ elem, "backgroundColor", "background-color") || cls.whiteColor();
+ },
+
+ /** @id MochiKit.Color.Color.fromText */
+ fromText: function (elem) {
+ var cls = MochiKit.Color.Color;
+ return cls.fromComputedStyle(
+ elem, "color", "color") || cls.blackColor();
+ },
+
+ /** @id MochiKit.Color.Color.namedColors */
+ namedColors: function () {
+ return MochiKit.Base.clone(MochiKit.Color.Color._namedColors);
+ }
+});
+
+
+// Module level functions
+
+MochiKit.Base.update(MochiKit.Color, {
+ /** @id MochiKit.Color.clampColorComponent */
+ clampColorComponent: function (v, scale) {
+ v *= scale;
+ if (v < 0) {
+ return 0;
+ } else if (v > scale) {
+ return scale;
+ } else {
+ return v;
+ }
+ },
+
+ _hslValue: function (n1, n2, hue) {
+ if (hue > 6.0) {
+ hue -= 6.0;
+ } else if (hue < 0.0) {
+ hue += 6.0;
+ }
+ var val;
+ if (hue < 1.0) {
+ val = n1 + (n2 - n1) * hue;
+ } else if (hue < 3.0) {
+ val = n2;
+ } else if (hue < 4.0) {
+ val = n1 + (n2 - n1) * (4.0 - hue);
+ } else {
+ val = n1;
+ }
+ return val;
+ },
+
+ /** @id MochiKit.Color.hsvToRGB */
+ hsvToRGB: function (hue, saturation, value, alpha) {
+ if (arguments.length == 1) {
+ var hsv = hue;
+ hue = hsv.h;
+ saturation = hsv.s;
+ value = hsv.v;
+ alpha = hsv.a;
+ }
+ var red;
+ var green;
+ var blue;
+ if (saturation === 0) {
+ red = value;
+ green = value;
+ blue = value;
+ } else {
+ var i = Math.floor(hue * 6);
+ var f = (hue * 6) - i;
+ var p = value * (1 - saturation);
+ var q = value * (1 - (saturation * f));
+ var t = value * (1 - (saturation * (1 - f)));
+ switch (i) {
+ case 1: red = q; green = value; blue = p; break;
+ case 2: red = p; green = value; blue = t; break;
+ case 3: red = p; green = q; blue = value; break;
+ case 4: red = t; green = p; blue = value; break;
+ case 5: red = value; green = p; blue = q; break;
+ case 6: // fall through
+ case 0: red = value; green = t; blue = p; break;
+ }
+ }
+ return {
+ r: red,
+ g: green,
+ b: blue,
+ a: alpha
+ };
+ },
+
+ /** @id MochiKit.Color.hslToRGB */
+ hslToRGB: function (hue, saturation, lightness, alpha) {
+ if (arguments.length == 1) {
+ var hsl = hue;
+ hue = hsl.h;
+ saturation = hsl.s;
+ lightness = hsl.l;
+ alpha = hsl.a;
+ }
+ var red;
+ var green;
+ var blue;
+ if (saturation === 0) {
+ red = lightness;
+ green = lightness;
+ blue = lightness;
+ } else {
+ var m2;
+ if (lightness <= 0.5) {
+ m2 = lightness * (1.0 + saturation);
+ } else {
+ m2 = lightness + saturation - (lightness * saturation);
+ }
+ var m1 = (2.0 * lightness) - m2;
+ var f = MochiKit.Color._hslValue;
+ var h6 = hue * 6.0;
+ red = f(m1, m2, h6 + 2);
+ green = f(m1, m2, h6);
+ blue = f(m1, m2, h6 - 2);
+ }
+ return {
+ r: red,
+ g: green,
+ b: blue,
+ a: alpha
+ };
+ },
+
+ /** @id MochiKit.Color.rgbToHSV */
+ rgbToHSV: function (red, green, blue, alpha) {
+ if (arguments.length == 1) {
+ var rgb = red;
+ red = rgb.r;
+ green = rgb.g;
+ blue = rgb.b;
+ alpha = rgb.a;
+ }
+ var max = Math.max(Math.max(red, green), blue);
+ var min = Math.min(Math.min(red, green), blue);
+ var hue;
+ var saturation;
+ var value = max;
+ if (min == max) {
+ hue = 0;
+ saturation = 0;
+ } else {
+ var delta = (max - min);
+ saturation = delta / max;
+
+ if (red == max) {
+ hue = (green - blue) / delta;
+ } else if (green == max) {
+ hue = 2 + ((blue - red) / delta);
+ } else {
+ hue = 4 + ((red - green) / delta);
+ }
+ hue /= 6;
+ if (hue < 0) {
+ hue += 1;
+ }
+ if (hue > 1) {
+ hue -= 1;
+ }
+ }
+ return {
+ h: hue,
+ s: saturation,
+ v: value,
+ a: alpha
+ };
+ },
+
+ /** @id MochiKit.Color.rgbToHSL */
+ rgbToHSL: function (red, green, blue, alpha) {
+ if (arguments.length == 1) {
+ var rgb = red;
+ red = rgb.r;
+ green = rgb.g;
+ blue = rgb.b;
+ alpha = rgb.a;
+ }
+ var max = Math.max(red, Math.max(green, blue));
+ var min = Math.min(red, Math.min(green, blue));
+ var hue;
+ var saturation;
+ var lightness = (max + min) / 2.0;
+ var delta = max - min;
+ if (delta === 0) {
+ hue = 0;
+ saturation = 0;
+ } else {
+ if (lightness <= 0.5) {
+ saturation = delta / (max + min);
+ } else {
+ saturation = delta / (2 - max - min);
+ }
+ if (red == max) {
+ hue = (green - blue) / delta;
+ } else if (green == max) {
+ hue = 2 + ((blue - red) / delta);
+ } else {
+ hue = 4 + ((red - green) / delta);
+ }
+ hue /= 6;
+ if (hue < 0) {
+ hue += 1;
+ }
+ if (hue > 1) {
+ hue -= 1;
+ }
+
+ }
+ return {
+ h: hue,
+ s: saturation,
+ l: lightness,
+ a: alpha
+ };
+ },
+
+ /** @id MochiKit.Color.toColorPart */
+ toColorPart: function (num) {
+ num = Math.round(num);
+ var digits = num.toString(16);
+ if (num < 16) {
+ return '0' + digits;
+ }
+ return digits;
+ },
+
+ __new__: function () {
+ var m = MochiKit.Base;
+ /** @id MochiKit.Color.Color.fromRGBString */
+ this.Color.fromRGBString = m.bind(
+ this.Color._fromColorString, this.Color, "rgb", "fromRGB",
+ [1.0/255.0, 1.0/255.0, 1.0/255.0, 1]
+ );
+ /** @id MochiKit.Color.Color.fromHSLString */
+ this.Color.fromHSLString = m.bind(
+ this.Color._fromColorString, this.Color, "hsl", "fromHSL",
+ [1.0/360.0, 0.01, 0.01, 1]
+ );
+
+ var third = 1.0 / 3.0;
+ /** @id MochiKit.Color.colors */
+ var colors = {
+ // NSColor colors plus transparent
+ /** @id MochiKit.Color.blackColor */
+ black: [0, 0, 0],
+ /** @id MochiKit.Color.blueColor */
+ blue: [0, 0, 1],
+ /** @id MochiKit.Color.brownColor */
+ brown: [0.6, 0.4, 0.2],
+ /** @id MochiKit.Color.cyanColor */
+ cyan: [0, 1, 1],
+ /** @id MochiKit.Color.darkGrayColor */
+ darkGray: [third, third, third],
+ /** @id MochiKit.Color.grayColor */
+ gray: [0.5, 0.5, 0.5],
+ /** @id MochiKit.Color.greenColor */
+ green: [0, 1, 0],
+ /** @id MochiKit.Color.lightGrayColor */
+ lightGray: [2 * third, 2 * third, 2 * third],
+ /** @id MochiKit.Color.magentaColor */
+ magenta: [1, 0, 1],
+ /** @id MochiKit.Color.orangeColor */
+ orange: [1, 0.5, 0],
+ /** @id MochiKit.Color.purpleColor */
+ purple: [0.5, 0, 0.5],
+ /** @id MochiKit.Color.redColor */
+ red: [1, 0, 0],
+ /** @id MochiKit.Color.transparentColor */
+ transparent: [0, 0, 0, 0],
+ /** @id MochiKit.Color.whiteColor */
+ white: [1, 1, 1],
+ /** @id MochiKit.Color.yellowColor */
+ yellow: [1, 1, 0]
+ };
+
+ for (var k in colors) {
+ var name = k + "Color";
+ var value = this.Color.fromRGB.apply(this.Color, colors[k]);
+ this.Color[name] = m.partial(m.operator.identity, value);
+ }
+
+ var isColor = function () {
+ for (var i = 0; i < arguments.length; i++) {
+ if (!(arguments[i] instanceof MochiKit.Color.Color)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ var compareColor = function (a, b) {
+ return a.compareRGB(b);
+ };
+
+ m.nameFunctions(this);
+
+ m.registerComparator(this.Color.NAME, isColor, compareColor);
+ }
+});
+
+MochiKit.Color.__new__();
+
+// Full table of css3 X11 colors
+
+MochiKit.Color.Color._namedColors = {
+ aliceblue: "#f0f8ff",
+ antiquewhite: "#faebd7",
+ aqua: "#00ffff",
+ aquamarine: "#7fffd4",
+ azure: "#f0ffff",
+ beige: "#f5f5dc",
+ bisque: "#ffe4c4",
+ black: "#000000",
+ blanchedalmond: "#ffebcd",
+ blue: "#0000ff",
+ blueviolet: "#8a2be2",
+ brown: "#a52a2a",
+ burlywood: "#deb887",
+ cadetblue: "#5f9ea0",
+ chartreuse: "#7fff00",
+ chocolate: "#d2691e",
+ coral: "#ff7f50",
+ cornflowerblue: "#6495ed",
+ cornsilk: "#fff8dc",
+ crimson: "#dc143c",
+ cyan: "#00ffff",
+ darkblue: "#00008b",
+ darkcyan: "#008b8b",
+ darkgoldenrod: "#b8860b",
+ darkgray: "#a9a9a9",
+ darkgreen: "#006400",
+ darkgrey: "#a9a9a9",
+ darkkhaki: "#bdb76b",
+ darkmagenta: "#8b008b",
+ darkolivegreen: "#556b2f",
+ darkorange: "#ff8c00",
+ darkorchid: "#9932cc",
+ darkred: "#8b0000",
+ darksalmon: "#e9967a",
+ darkseagreen: "#8fbc8f",
+ darkslateblue: "#483d8b",
+ darkslategray: "#2f4f4f",
+ darkslategrey: "#2f4f4f",
+ darkturquoise: "#00ced1",
+ darkviolet: "#9400d3",
+ deeppink: "#ff1493",
+ deepskyblue: "#00bfff",
+ dimgray: "#696969",
+ dimgrey: "#696969",
+ dodgerblue: "#1e90ff",
+ firebrick: "#b22222",
+ floralwhite: "#fffaf0",
+ forestgreen: "#228b22",
+ fuchsia: "#ff00ff",
+ gainsboro: "#dcdcdc",
+ ghostwhite: "#f8f8ff",
+ gold: "#ffd700",
+ goldenrod: "#daa520",
+ gray: "#808080",
+ green: "#008000",
+ greenyellow: "#adff2f",
+ grey: "#808080",
+ honeydew: "#f0fff0",
+ hotpink: "#ff69b4",
+ indianred: "#cd5c5c",
+ indigo: "#4b0082",
+ ivory: "#fffff0",
+ khaki: "#f0e68c",
+ lavender: "#e6e6fa",
+ lavenderblush: "#fff0f5",
+ lawngreen: "#7cfc00",
+ lemonchiffon: "#fffacd",
+ lightblue: "#add8e6",
+ lightcoral: "#f08080",
+ lightcyan: "#e0ffff",
+ lightgoldenrodyellow: "#fafad2",
+ lightgray: "#d3d3d3",
+ lightgreen: "#90ee90",
+ lightgrey: "#d3d3d3",
+ lightpink: "#ffb6c1",
+ lightsalmon: "#ffa07a",
+ lightseagreen: "#20b2aa",
+ lightskyblue: "#87cefa",
+ lightslategray: "#778899",
+ lightslategrey: "#778899",
+ lightsteelblue: "#b0c4de",
+ lightyellow: "#ffffe0",
+ lime: "#00ff00",
+ limegreen: "#32cd32",
+ linen: "#faf0e6",
+ magenta: "#ff00ff",
+ maroon: "#800000",
+ mediumaquamarine: "#66cdaa",
+ mediumblue: "#0000cd",
+ mediumorchid: "#ba55d3",
+ mediumpurple: "#9370db",
+ mediumseagreen: "#3cb371",
+ mediumslateblue: "#7b68ee",
+ mediumspringgreen: "#00fa9a",
+ mediumturquoise: "#48d1cc",
+ mediumvioletred: "#c71585",
+ midnightblue: "#191970",
+ mintcream: "#f5fffa",
+ mistyrose: "#ffe4e1",
+ moccasin: "#ffe4b5",
+ navajowhite: "#ffdead",
+ navy: "#000080",
+ oldlace: "#fdf5e6",
+ olive: "#808000",
+ olivedrab: "#6b8e23",
+ orange: "#ffa500",
+ orangered: "#ff4500",
+ orchid: "#da70d6",
+ palegoldenrod: "#eee8aa",
+ palegreen: "#98fb98",
+ paleturquoise: "#afeeee",
+ palevioletred: "#db7093",
+ papayawhip: "#ffefd5",
+ peachpuff: "#ffdab9",
+ peru: "#cd853f",
+ pink: "#ffc0cb",
+ plum: "#dda0dd",
+ powderblue: "#b0e0e6",
+ purple: "#800080",
+ red: "#ff0000",
+ rosybrown: "#bc8f8f",
+ royalblue: "#4169e1",
+ saddlebrown: "#8b4513",
+ salmon: "#fa8072",
+ sandybrown: "#f4a460",
+ seagreen: "#2e8b57",
+ seashell: "#fff5ee",
+ sienna: "#a0522d",
+ silver: "#c0c0c0",
+ skyblue: "#87ceeb",
+ slateblue: "#6a5acd",
+ slategray: "#708090",
+ slategrey: "#708090",
+ snow: "#fffafa",
+ springgreen: "#00ff7f",
+ steelblue: "#4682b4",
+ tan: "#d2b48c",
+ teal: "#008080",
+ thistle: "#d8bfd8",
+ tomato: "#ff6347",
+ turquoise: "#40e0d0",
+ violet: "#ee82ee",
+ wheat: "#f5deb3",
+ white: "#ffffff",
+ whitesmoke: "#f5f5f5",
+ yellow: "#ffff00",
+ yellowgreen: "#9acd32"
+};
+
+MochiKit.Base._exportSymbols(this, MochiKit.Color);
diff --git a/frontend/delta/js/MochiKit/DOM.js b/frontend/delta/js/MochiKit/DOM.js
new file mode 100644
index 0000000..23d996b
--- /dev/null
+++ b/frontend/delta/js/MochiKit/DOM.js
@@ -0,0 +1,1202 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.DOM 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'DOM', '1.5', ['Base']);
+
+MochiKit.Base.update(MochiKit.DOM, {
+
+ /** @id MochiKit.DOM.currentWindow */
+ currentWindow: function () {
+ return MochiKit.DOM._window;
+ },
+
+ /** @id MochiKit.DOM.currentDocument */
+ currentDocument: function () {
+ return MochiKit.DOM._document;
+ },
+
+ /** @id MochiKit.DOM.withWindow */
+ withWindow: function (win, func) {
+ var self = MochiKit.DOM;
+ var oldDoc = self._document;
+ var oldWin = self._window;
+ var rval;
+ try {
+ self._window = win;
+ self._document = win.document;
+ rval = func();
+ } catch (e) {
+ self._window = oldWin;
+ self._document = oldDoc;
+ throw e;
+ }
+ self._window = oldWin;
+ self._document = oldDoc;
+ return rval;
+ },
+
+ /** @id MochiKit.DOM.formContents */
+ formContents: function (elem/* = document.body */) {
+ var names = [];
+ var values = [];
+ var m = MochiKit.Base;
+ var self = MochiKit.DOM;
+ if (typeof(elem) == "undefined" || elem === null) {
+ elem = self._document.body;
+ } else {
+ elem = self.getElement(elem);
+ }
+ m.nodeWalk(elem, function (elem) {
+ var name = elem.name;
+ if (m.isNotEmpty(name)) {
+ var tagName = elem.tagName.toUpperCase();
+ if (tagName === "INPUT"
+ && (elem.type == "radio" || elem.type == "checkbox")
+ && !elem.checked
+ ) {
+ return null;
+ }
+ if (tagName === "SELECT") {
+ if (elem.type == "select-one") {
+ if (elem.selectedIndex >= 0) {
+ var opt = elem.options[elem.selectedIndex];
+ var v = opt.value;
+ if (!v) {
+ var h = opt.outerHTML;
+ // internet explorer sure does suck.
+ if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
+ v = opt.text;
+ }
+ }
+ names.push(name);
+ values.push(v);
+ return null;
+ }
+ // no form elements?
+ names.push(name);
+ values.push("");
+ return null;
+ } else {
+ var opts = elem.options;
+ if (!opts.length) {
+ names.push(name);
+ values.push("");
+ return null;
+ }
+ for (var i = 0; i < opts.length; i++) {
+ var opt = opts[i];
+ if (!opt.selected) {
+ continue;
+ }
+ var v = opt.value;
+ if (!v) {
+ var h = opt.outerHTML;
+ // internet explorer sure does suck.
+ if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
+ v = opt.text;
+ }
+ }
+ names.push(name);
+ values.push(v);
+ }
+ return null;
+ }
+ }
+ if (tagName === "FORM" || tagName === "P" || tagName === "SPAN"
+ || tagName === "DIV"
+ ) {
+ return elem.childNodes;
+ }
+ names.push(name);
+ values.push(elem.value || '');
+ return null;
+ }
+ return elem.childNodes;
+ });
+ return [names, values];
+ },
+
+ /** @id MochiKit.DOM.withDocument */
+ withDocument: function (doc, func) {
+ var self = MochiKit.DOM;
+ var oldDoc = self._document;
+ var rval;
+ try {
+ self._document = doc;
+ rval = func();
+ } catch (e) {
+ self._document = oldDoc;
+ throw e;
+ }
+ self._document = oldDoc;
+ return rval;
+ },
+
+ /** @id MochiKit.DOM.registerDOMConverter */
+ registerDOMConverter: function (name, check, wrap, /* optional */override) {
+ MochiKit.DOM.domConverters.register(name, check, wrap, override);
+ },
+
+ /** @id MochiKit.DOM.coerceToDOM */
+ coerceToDOM: function (node, ctx) {
+ var m = MochiKit.Base;
+ var im = MochiKit.Iter;
+ var self = MochiKit.DOM;
+ if (im) {
+ var iter = im.iter;
+ var repeat = im.repeat;
+ }
+ var map = m.map;
+ var domConverters = self.domConverters;
+ var coerceToDOM = arguments.callee;
+ var NotFound = m.NotFound;
+ while (true) {
+ if (typeof(node) == 'undefined' || node === null) {
+ return null;
+ }
+ // this is a safari childNodes object, avoiding crashes w/ attr
+ // lookup
+ if (typeof(node) == "function" &&
+ typeof(node.length) == "number" &&
+ !(node instanceof Function)) {
+ node = im ? im.list(node) : m.extend(null, node);
+ }
+ if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) {
+ return node;
+ }
+ if (typeof(node) == 'number' || typeof(node) == 'boolean') {
+ node = node.toString();
+ // FALL THROUGH
+ }
+ if (typeof(node) == 'string') {
+ return self._document.createTextNode(node);
+ }
+ if (typeof(node.__dom__) == 'function') {
+ node = node.__dom__(ctx);
+ continue;
+ }
+ if (typeof(node.dom) == 'function') {
+ node = node.dom(ctx);
+ continue;
+ }
+ if (typeof(node) == 'function') {
+ node = node.apply(ctx, [ctx]);
+ continue;
+ }
+
+ if (im) {
+ // iterable
+ var iterNodes = null;
+ try {
+ iterNodes = iter(node);
+ } catch (e) {
+ // pass
+ }
+ if (iterNodes) {
+ return map(coerceToDOM, iterNodes, repeat(ctx));
+ }
+ } else if (m.isArrayLike(node)) {
+ var func = function (n) { return coerceToDOM(n, ctx); };
+ return map(func, node);
+ }
+
+ // adapter
+ try {
+ node = domConverters.match(node, ctx);
+ continue;
+ } catch (e) {
+ if (e != NotFound) {
+ throw e;
+ }
+ }
+
+ // fallback
+ return self._document.createTextNode(node.toString());
+ }
+ // mozilla warnings aren't too bright
+ return undefined;
+ },
+
+ /** @id MochiKit.DOM.isChildNode */
+ isChildNode: function (node, maybeparent) {
+ var self = MochiKit.DOM;
+ if (typeof(node) == "string") {
+ node = self.getElement(node);
+ }
+ if (typeof(maybeparent) == "string") {
+ maybeparent = self.getElement(maybeparent);
+ }
+ if (typeof(node) == 'undefined' || node === null) {
+ return false;
+ }
+ while (node != null && node !== self._document) {
+ if (node === maybeparent) {
+ return true;
+ }
+ node = node.parentNode;
+ }
+ return false;
+ },
+
+ /** @id MochiKit.DOM.setNodeAttribute */
+ setNodeAttribute: function (node, attr, value) {
+ var o = {};
+ o[attr] = value;
+ try {
+ return MochiKit.DOM.updateNodeAttributes(node, o);
+ } catch (e) {
+ // pass
+ }
+ return null;
+ },
+
+ /** @id MochiKit.DOM.getNodeAttribute */
+ getNodeAttribute: function (node, attr) {
+ var self = MochiKit.DOM;
+ var rename = self.attributeArray.renames[attr];
+ var ignoreValue = self.attributeArray.ignoreAttr[attr];
+ node = self.getElement(node);
+ try {
+ if (rename) {
+ return node[rename];
+ }
+ var value = node.getAttribute(attr);
+ if (value != ignoreValue) {
+ return value;
+ }
+ } catch (e) {
+ // pass
+ }
+ return null;
+ },
+
+ /** @id MochiKit.DOM.removeNodeAttribute */
+ removeNodeAttribute: function (node, attr) {
+ var self = MochiKit.DOM;
+ var rename = self.attributeArray.renames[attr];
+ node = self.getElement(node);
+ try {
+ if (rename) {
+ return node[rename];
+ }
+ return node.removeAttribute(attr);
+ } catch (e) {
+ // pass
+ }
+ return null;
+ },
+
+ /** @id MochiKit.DOM.updateNodeAttributes */
+ updateNodeAttributes: function (node, attrs) {
+ var elem = node;
+ var self = MochiKit.DOM;
+ var base = MochiKit.Base;
+ if (typeof(node) == 'string') {
+ elem = self.getElement(node);
+ }
+ if (attrs) {
+ if (self.attributeArray.compliant) {
+ // not IE, good.
+ for (var k in attrs) {
+ var v = attrs[k];
+ if (typeof(v) == 'object' && typeof(elem[k]) == 'object') {
+ if (k == "style" && MochiKit.Style) {
+ MochiKit.Style.setStyle(elem, v);
+ } else {
+ base.updatetree(elem[k], v);
+ }
+ } else if (k.substring(0, 2) == "on") {
+ if (typeof(v) == "string") {
+ v = new Function(v);
+ }
+ elem[k] = v;
+ } else {
+ elem.setAttribute(k, v);
+ }
+ if (base.isValue(elem[k]) && elem[k] != v) {
+ // Also set property for weird attributes (see #302 & #335)
+ elem[k] = v;
+ }
+ }
+ } else {
+ // IE is insane in the membrane
+ var renames = self.attributeArray.renames;
+ for (var k in attrs) {
+ v = attrs[k];
+ var renamed = renames[k];
+ if (k == "style" && typeof(v) == "string") {
+ elem.style.cssText = v;
+ } else if (typeof(renamed) == "string") {
+ elem[renamed] = v;
+ } else if (typeof(elem[k]) == 'object'
+ && typeof(v) == 'object') {
+ if (k == "style" && MochiKit.Style) {
+ MochiKit.Style.setStyle(elem, v);
+ } else {
+ base.updatetree(elem[k], v);
+ }
+ } else if (k.substring(0, 2) == "on") {
+ if (typeof(v) == "string") {
+ v = new Function(v);
+ }
+ elem[k] = v;
+ } else {
+ elem.setAttribute(k, v);
+ }
+ if (base.isValue(elem[k]) && elem[k] != v) {
+ // Also set property for weird attributes (see #302 & #335)
+ elem[k] = v;
+ }
+ }
+ }
+ }
+ return elem;
+ },
+
+ /** @id MochiKit.DOM.appendChildNodes */
+ appendChildNodes: function (node/*, nodes...*/) {
+ var elem = node;
+ var self = MochiKit.DOM;
+ if (typeof(node) == 'string') {
+ elem = self.getElement(node);
+ }
+ var nodeStack = [
+ self.coerceToDOM(
+ MochiKit.Base.extend(null, arguments, 1),
+ elem
+ )
+ ];
+ var concat = MochiKit.Base.concat;
+ while (nodeStack.length) {
+ var n = nodeStack.shift();
+ if (typeof(n) == 'undefined' || n === null) {
+ // pass
+ } else if (typeof(n.nodeType) == 'number') {
+ elem.appendChild(n);
+ } else {
+ nodeStack = concat(n, nodeStack);
+ }
+ }
+ return elem;
+ },
+
+
+ /** @id MochiKit.DOM.insertSiblingNodesBefore */
+ insertSiblingNodesBefore: function (node/*, nodes...*/) {
+ var elem = node;
+ var self = MochiKit.DOM;
+ if (typeof(node) == 'string') {
+ elem = self.getElement(node);
+ }
+ var nodeStack = [
+ self.coerceToDOM(
+ MochiKit.Base.extend(null, arguments, 1),
+ elem
+ )
+ ];
+ var parentnode = elem.parentNode;
+ var concat = MochiKit.Base.concat;
+ while (nodeStack.length) {
+ var n = nodeStack.shift();
+ if (typeof(n) == 'undefined' || n === null) {
+ // pass
+ } else if (typeof(n.nodeType) == 'number') {
+ parentnode.insertBefore(n, elem);
+ } else {
+ nodeStack = concat(n, nodeStack);
+ }
+ }
+ return parentnode;
+ },
+
+ /** @id MochiKit.DOM.insertSiblingNodesAfter */
+ insertSiblingNodesAfter: function (node/*, nodes...*/) {
+ var elem = node;
+ var self = MochiKit.DOM;
+
+ if (typeof(node) == 'string') {
+ elem = self.getElement(node);
+ }
+ var nodeStack = [
+ self.coerceToDOM(
+ MochiKit.Base.extend(null, arguments, 1),
+ elem
+ )
+ ];
+
+ if (elem.nextSibling) {
+ return self.insertSiblingNodesBefore(elem.nextSibling, nodeStack);
+ }
+ else {
+ return self.appendChildNodes(elem.parentNode, nodeStack);
+ }
+ },
+
+ /** @id MochiKit.DOM.replaceChildNodes */
+ replaceChildNodes: function (node/*, nodes...*/) {
+ var elem = node;
+ var self = MochiKit.DOM;
+ if (typeof(node) == 'string') {
+ elem = self.getElement(node);
+ arguments[0] = elem;
+ }
+ var child;
+ while ((child = elem.firstChild)) {
+ elem.removeChild(child);
+ }
+ if (arguments.length < 2) {
+ return elem;
+ } else {
+ return self.appendChildNodes.apply(this, arguments);
+ }
+ },
+
+ /** @id MochiKit.DOM.createDOM */
+ createDOM: function (name, attrs/*, nodes... */) {
+ var elem;
+ var self = MochiKit.DOM;
+ var m = MochiKit.Base;
+ if (typeof(attrs) == "string" || typeof(attrs) == "number") {
+ var args = m.extend([name, null], arguments, 1);
+ return arguments.callee.apply(this, args);
+ }
+ if (typeof(name) == 'string') {
+ // Internet Explorer is dumb
+ var xhtml = self._xhtml;
+ if (attrs && !self.attributeArray.compliant) {
+ // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
+ var contents = "";
+ if ('name' in attrs) {
+ contents += ' name="' + self.escapeHTML(attrs.name) + '"';
+ }
+ if (name == 'input' && 'type' in attrs) {
+ contents += ' type="' + self.escapeHTML(attrs.type) + '"';
+ }
+ if (contents) {
+ name = "<" + name + contents + ">";
+ xhtml = false;
+ }
+ }
+ var d = self._document;
+ if (xhtml && d === document) {
+ elem = d.createElementNS("http://www.w3.org/1999/xhtml", name);
+ } else {
+ elem = d.createElement(name);
+ }
+ } else {
+ elem = name;
+ }
+ if (attrs) {
+ self.updateNodeAttributes(elem, attrs);
+ }
+ if (arguments.length <= 2) {
+ return elem;
+ } else {
+ var args = m.extend([elem], arguments, 2);
+ return self.appendChildNodes.apply(this, args);
+ }
+ },
+
+ /** @id MochiKit.DOM.createDOMFunc */
+ createDOMFunc: function (/* tag, attrs, *nodes */) {
+ var m = MochiKit.Base;
+ return m.partial.apply(
+ this,
+ m.extend([MochiKit.DOM.createDOM], arguments)
+ );
+ },
+
+ /** @id MochiKit.DOM.removeElement */
+ removeElement: function (elem) {
+ var self = MochiKit.DOM;
+ if (typeof(elem) == "string") {
+ elem = self.getElement(elem);
+ }
+ var e = self.coerceToDOM(elem);
+ e.parentNode.removeChild(e);
+ return e;
+ },
+
+ /** @id MochiKit.DOM.swapDOM */
+ swapDOM: function (dest, src) {
+ var self = MochiKit.DOM;
+ dest = self.getElement(dest);
+ var parent = dest.parentNode;
+ if (src) {
+ if (typeof(src) == "string") {
+ src = self.getElement(src);
+ }
+ src = self.coerceToDOM(src, parent);
+ parent.replaceChild(src, dest);
+ } else {
+ parent.removeChild(dest);
+ }
+ return src;
+ },
+
+ /** @id MochiKit.DOM.getElement */
+ getElement: function (id) {
+ var self = MochiKit.DOM;
+ if (arguments.length == 1) {
+ return ((typeof(id) == "string") ?
+ self._document.getElementById(id) : id);
+ } else {
+ return MochiKit.Base.map(self.getElement, arguments);
+ }
+ },
+
+ /** @id MochiKit.DOM.getElementsByTagAndClassName */
+ getElementsByTagAndClassName: function (tagName, className,
+ /* optional */parent) {
+ var self = MochiKit.DOM;
+ if (typeof(tagName) == 'undefined' || tagName === null) {
+ tagName = '*';
+ }
+ if (typeof(parent) == 'undefined' || parent === null) {
+ parent = self._document;
+ }
+ parent = self.getElement(parent);
+ if (parent == null) {
+ return [];
+ }
+ var children = (parent.getElementsByTagName(tagName)
+ || self._document.all);
+ if (typeof(className) == 'undefined' || className === null) {
+ return MochiKit.Base.extend(null, children);
+ }
+
+ var elements = [];
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ var cls = child.className;
+ if (typeof(cls) != "string") {
+ cls = child.getAttribute("class");
+ }
+ if (typeof(cls) == "string") {
+ var classNames = cls.split(' ');
+ for (var j = 0; j < classNames.length; j++) {
+ if (classNames[j] == className) {
+ elements.push(child);
+ break;
+ }
+ }
+ }
+ }
+
+ return elements;
+ },
+
+ _newCallStack: function (path, once) {
+ var rval = function () {
+ var callStack = arguments.callee.callStack;
+ for (var i = 0; i < callStack.length; i++) {
+ if (callStack[i].apply(this, arguments) === false) {
+ break;
+ }
+ }
+ if (once) {
+ try {
+ this[path] = null;
+ } catch (e) {
+ // pass
+ }
+ }
+ };
+ rval.callStack = [];
+ return rval;
+ },
+
+ /** @id MochiKit.DOM.addToCallStack */
+ addToCallStack: function (target, path, func, once) {
+ var self = MochiKit.DOM;
+ var existing = target[path];
+ var regfunc = existing;
+ if (!(typeof(existing) == 'function'
+ && typeof(existing.callStack) == "object"
+ && existing.callStack !== null)) {
+ regfunc = self._newCallStack(path, once);
+ if (typeof(existing) == 'function') {
+ regfunc.callStack.push(existing);
+ }
+ target[path] = regfunc;
+ }
+ regfunc.callStack.push(func);
+ },
+
+ /** @id MochiKit.DOM.addLoadEvent */
+ addLoadEvent: function (func) {
+ var self = MochiKit.DOM;
+ self.addToCallStack(self._window, "onload", func, true);
+
+ },
+
+ /** @id MochiKit.DOM.focusOnLoad */
+ focusOnLoad: function (element) {
+ var self = MochiKit.DOM;
+ self.addLoadEvent(function () {
+ element = self.getElement(element);
+ if (element) {
+ element.focus();
+ }
+ });
+ },
+
+ /** @id MochiKit.DOM.setElementClass */
+ setElementClass: function (element, className) {
+ var self = MochiKit.DOM;
+ var obj = self.getElement(element);
+ if (self.attributeArray.compliant) {
+ obj.setAttribute("class", className);
+ } else {
+ obj.setAttribute("className", className);
+ }
+ },
+
+ /** @id MochiKit.DOM.toggleElementClass */
+ toggleElementClass: function (className/*, element... */) {
+ var self = MochiKit.DOM;
+ for (var i = 1; i < arguments.length; i++) {
+ var obj = self.getElement(arguments[i]);
+ if (!self.addElementClass(obj, className)) {
+ self.removeElementClass(obj, className);
+ }
+ }
+ },
+
+ /** @id MochiKit.DOM.addElementClass */
+ addElementClass: function (element, className) {
+ var self = MochiKit.DOM;
+ var obj = self.getElement(element);
+ var cls = obj.className;
+ if (typeof(cls) != "string") {
+ cls = obj.getAttribute("class");
+ }
+ // trivial case, no className yet
+ if (typeof(cls) != "string" || cls.length === 0) {
+ self.setElementClass(obj, className);
+ return true;
+ }
+ // the other trivial case, already set as the only class
+ if (cls == className) {
+ return false;
+ }
+ var classes = cls.split(" ");
+ for (var i = 0; i < classes.length; i++) {
+ // already present
+ if (classes[i] == className) {
+ return false;
+ }
+ }
+ // append class
+ self.setElementClass(obj, cls + " " + className);
+ return true;
+ },
+
+ /** @id MochiKit.DOM.removeElementClass */
+ removeElementClass: function (element, className) {
+ var self = MochiKit.DOM;
+ var obj = self.getElement(element);
+ var cls = obj.className;
+ if (typeof(cls) != "string") {
+ cls = obj.getAttribute("class");
+ }
+ // trivial case, no className yet
+ if (typeof(cls) != "string" || cls.length === 0) {
+ return false;
+ }
+ // other trivial case, set only to className
+ if (cls == className) {
+ self.setElementClass(obj, "");
+ return true;
+ }
+ var classes = cls.split(" ");
+ for (var i = 0; i < classes.length; i++) {
+ // already present
+ if (classes[i] == className) {
+ // only check sane case where the class is used once
+ classes.splice(i, 1);
+ self.setElementClass(obj, classes.join(" "));
+ return true;
+ }
+ }
+ // not found
+ return false;
+ },
+
+ /** @id MochiKit.DOM.swapElementClass */
+ swapElementClass: function (element, fromClass, toClass) {
+ var obj = MochiKit.DOM.getElement(element);
+ var res = MochiKit.DOM.removeElementClass(obj, fromClass);
+ if (res) {
+ MochiKit.DOM.addElementClass(obj, toClass);
+ }
+ return res;
+ },
+
+ /** @id MochiKit.DOM.hasElementClass */
+ hasElementClass: function (element, className/*...*/) {
+ var obj = MochiKit.DOM.getElement(element);
+ if (obj == null) {
+ return false;
+ }
+ var cls = obj.className;
+ if (typeof(cls) != "string" && typeof(obj.getAttribute) == "function") {
+ cls = obj.getAttribute("class");
+ }
+ if (typeof(cls) != "string") {
+ return false;
+ }
+ var classes = cls.split(" ");
+ for (var i = 1; i < arguments.length; i++) {
+ var good = false;
+ for (var j = 0; j < classes.length; j++) {
+ if (classes[j] == arguments[i]) {
+ good = true;
+ break;
+ }
+ }
+ if (!good) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /** @id MochiKit.DOM.escapeHTML */
+ escapeHTML: function (s) {
+ return s.replace(/&/g, "&"
+ ).replace(/"/g, """
+ ).replace(//g, ">");
+ },
+
+ /** @id MochiKit.DOM.toHTML */
+ toHTML: function (dom) {
+ return MochiKit.DOM.emitHTML(dom).join("");
+ },
+
+ /** @id MochiKit.DOM.emitHTML */
+ emitHTML: function (dom, /* optional */lst) {
+ if (typeof(lst) == 'undefined' || lst === null) {
+ lst = [];
+ }
+ // queue is the call stack, we're doing this non-recursively
+ var queue = [dom];
+ var self = MochiKit.DOM;
+ var escapeHTML = self.escapeHTML;
+ var attributeArray = self.attributeArray;
+ while (queue.length) {
+ dom = queue.pop();
+ if (typeof(dom) == 'string') {
+ lst.push(dom);
+ } else if (dom.nodeType == 1) {
+ // we're not using higher order stuff here
+ // because safari has heisenbugs.. argh.
+ //
+ // I think it might have something to do with
+ // garbage collection and function calls.
+ lst.push('<' + dom.tagName.toLowerCase());
+ var attributes = [];
+ var domAttr = attributeArray(dom);
+ for (var i = 0; i < domAttr.length; i++) {
+ var a = domAttr[i];
+ attributes.push([
+ " ",
+ a.name,
+ '="',
+ escapeHTML(a.value),
+ '"'
+ ]);
+ }
+ attributes.sort();
+ for (i = 0; i < attributes.length; i++) {
+ var attrs = attributes[i];
+ for (var j = 0; j < attrs.length; j++) {
+ lst.push(attrs[j]);
+ }
+ }
+ if (dom.hasChildNodes()) {
+ lst.push(">");
+ // queue is the FILO call stack, so we put the close tag
+ // on first
+ queue.push("" + dom.tagName.toLowerCase() + ">");
+ var cnodes = dom.childNodes;
+ for (i = cnodes.length - 1; i >= 0; i--) {
+ queue.push(cnodes[i]);
+ }
+ } else {
+ lst.push('/>');
+ }
+ } else if (dom.nodeType == 3) {
+ lst.push(escapeHTML(dom.nodeValue));
+ }
+ }
+ return lst;
+ },
+
+ /** @id MochiKit.DOM.scrapeText */
+ scrapeText: function (node, /* optional */asArray) {
+ var rval = [];
+ (function (node) {
+ var cn = node.childNodes;
+ if (cn) {
+ for (var i = 0; i < cn.length; i++) {
+ arguments.callee.call(this, cn[i]);
+ }
+ }
+ var nodeValue = node.nodeValue;
+ if (typeof(nodeValue) == 'string') {
+ rval.push(nodeValue);
+ }
+ })(MochiKit.DOM.getElement(node));
+ if (asArray) {
+ return rval;
+ } else {
+ return rval.join("");
+ }
+ },
+
+ /** @id MochiKit.DOM.removeEmptyTextNodes */
+ removeEmptyTextNodes: function (element) {
+ element = MochiKit.DOM.getElement(element);
+ for (var i = 0; i < element.childNodes.length; i++) {
+ var node = element.childNodes[i];
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
+ node.parentNode.removeChild(node);
+ }
+ }
+ },
+
+ /** @id MochiKit.DOM.getFirstElementByTagAndClassName */
+ getFirstElementByTagAndClassName: function (tagName, className,
+ /* optional */parent) {
+ var self = MochiKit.DOM;
+ if (typeof(tagName) == 'undefined' || tagName === null) {
+ tagName = '*';
+ }
+ if (typeof(parent) == 'undefined' || parent === null) {
+ parent = self._document;
+ }
+ parent = self.getElement(parent);
+ if (parent == null) {
+ return null;
+ }
+ var children = (parent.getElementsByTagName(tagName)
+ || self._document.all);
+ if (children.length <= 0) {
+ return null;
+ } else if (typeof(className) == 'undefined' || className === null) {
+ return children[0];
+ }
+
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ var cls = child.className;
+ if (typeof(cls) != "string") {
+ cls = child.getAttribute("class");
+ }
+ if (typeof(cls) == "string") {
+ var classNames = cls.split(' ');
+ for (var j = 0; j < classNames.length; j++) {
+ if (classNames[j] == className) {
+ return child;
+ }
+ }
+ }
+ }
+ return null;
+ },
+
+ /** @id MochiKit.DOM.getFirstParentByTagAndClassName */
+ getFirstParentByTagAndClassName: function (elem, tagName, className) {
+ var self = MochiKit.DOM;
+ elem = self.getElement(elem);
+ if (typeof(tagName) == 'undefined' || tagName === null) {
+ tagName = '*';
+ } else {
+ tagName = tagName.toUpperCase();
+ }
+ if (typeof(className) == 'undefined' || className === null) {
+ className = null;
+ }
+ if (elem) {
+ elem = elem.parentNode;
+ }
+ while (elem && elem.tagName) {
+ var curTagName = elem.tagName.toUpperCase();
+ if ((tagName === '*' || tagName == curTagName) &&
+ (className === null || self.hasElementClass(elem, className))) {
+ return elem;
+ }
+ elem = elem.parentNode;
+ }
+ return null;
+ },
+
+ __new__: function (win) {
+
+ var m = MochiKit.Base;
+ if (typeof(document) != "undefined") {
+ this._document = document;
+ var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ this._xhtml = (document.documentElement &&
+ document.createElementNS &&
+ document.documentElement.namespaceURI === kXULNSURI);
+ } else if (MochiKit.MockDOM) {
+ this._document = MochiKit.MockDOM.document;
+ }
+ this._window = win;
+
+ this.domConverters = new m.AdapterRegistry();
+
+ var __tmpElement = this._document.createElement("span");
+ var attributeArray;
+ if (__tmpElement && __tmpElement.attributes &&
+ __tmpElement.attributes.length > 0) {
+ // for braindead browsers (IE) that insert extra junk
+ var filter = m.filter;
+ attributeArray = function (node) {
+ /***
+
+ Return an array of attributes for a given node,
+ filtering out attributes that don't belong for
+ that are inserted by "Certain Browsers".
+
+ ***/
+ return filter(attributeArray.ignoreAttrFilter, node.attributes);
+ };
+ attributeArray.ignoreAttr = {};
+ var attrs = __tmpElement.attributes;
+ var ignoreAttr = attributeArray.ignoreAttr;
+ for (var i = 0; i < attrs.length; i++) {
+ var a = attrs[i];
+ ignoreAttr[a.name] = a.value;
+ }
+ attributeArray.ignoreAttrFilter = function (a) {
+ return (attributeArray.ignoreAttr[a.name] != a.value);
+ };
+ attributeArray.compliant = false;
+ attributeArray.renames = {
+ "class": "className",
+ "checked": "defaultChecked",
+ "usemap": "useMap",
+ "for": "htmlFor",
+ "readonly": "readOnly",
+ "colspan": "colSpan",
+ "rowspan": "rowSpan",
+ "bgcolor": "bgColor",
+ "cellspacing": "cellSpacing",
+ "cellpadding": "cellPadding"
+ };
+ } else {
+ attributeArray = function (node) {
+ return node.attributes;
+ };
+ attributeArray.compliant = true;
+ attributeArray.ignoreAttr = {};
+ attributeArray.renames = {};
+ }
+ attributeArray.__export__ = false;
+ this.attributeArray = attributeArray;
+
+ // Backwards compatibility aliases
+ /** @id MochiKit.DOM.computedStyle */
+ m._deprecated(this, 'computedStyle', 'MochiKit.Style.getStyle', '1.4', true);
+ /** @id MochiKit.DOM.elementDimensions */
+ m._deprecated(this, 'elementDimensions', 'MochiKit.Style.getElementDimensions', '1.4');
+ /** @id MochiKit.DOM.elementPosition */
+ m._deprecated(this, 'elementPosition', 'MochiKit.Style.getElementPosition', '1.4');
+ /** @id MochiKit.DOM.getViewportDimensions */
+ m._deprecated(this, 'getViewportDimensions', 'MochiKit.Style.getViewportDimensions', '1.4');
+ /** @id MochiKit.DOM.hideElement */
+ m._deprecated(this, 'hideElement', 'MochiKit.Style.hideElement', '1.4');
+ /** @id MochiKit.DOM.makeClipping */
+ m._deprecated(this, 'makeClipping', 'MochiKit.Style.makeClipping', '1.4.1');
+ /** @id MochiKit.DOM.makePositioned */
+ m._deprecated(this, 'makePositioned', 'MochiKit.Style.makePositioned', '1.4.1');
+ /** @id MochiKit.DOM.setElementDimensions */
+ m._deprecated(this, 'setElementDimensions', 'MochiKit.Style.setElementDimensions', '1.4');
+ /** @id MochiKit.DOM.setElementPosition */
+ m._deprecated(this, 'setElementPosition', 'MochiKit.Style.setElementPosition', '1.4');
+ /** @id MochiKit.DOM.setDisplayForElement */
+ m._deprecated(this, 'setDisplayForElement', 'MochiKit.Style.setDisplayForElement', '1.4');
+ /** @id MochiKit.DOM.setOpacity */
+ m._deprecated(this, 'setOpacity', 'MochiKit.Style.setOpacity', '1.4');
+ /** @id MochiKit.DOM.showElement */
+ m._deprecated(this, 'showElement', 'MochiKit.Style.showElement', '1.4');
+ /** @id MochiKit.DOM.undoClipping */
+ m._deprecated(this, 'undoClipping', 'MochiKit.Style.undoClipping', '1.4.1');
+ /** @id MochiKit.DOM.undoPositioned */
+ m._deprecated(this, 'undoPositioned', 'MochiKit.Style.undoPositioned', '1.4.1');
+ /** @id MochiKit.DOM.Coordinates */
+ m._deprecated(this, 'Coordinates', 'MochiKit.Style.Coordinates', '1.4');
+ /** @id MochiKit.DOM.Dimensions */
+ m._deprecated(this, 'Dimensions', 'MochiKit.Style.Dimensions', '1.4');
+
+ // shorthand for createDOM syntax
+ var createDOMFunc = this.createDOMFunc;
+ /** @id MochiKit.DOM.A */
+ this.A = createDOMFunc("a");
+ /** @id MochiKit.DOM.ARTICLE */
+ this.ARTICLE = createDOMFunc("article");
+ /** @id MochiKit.DOM.ASIDE */
+ this.ASIDE = createDOMFunc("aside");
+ /** @id MochiKit.DOM.BR */
+ this.BR = createDOMFunc("br");
+ /** @id MochiKit.DOM.BUTTON */
+ this.BUTTON = createDOMFunc("button");
+ /** @id MochiKit.DOM.CANVAS */
+ this.CANVAS = createDOMFunc("canvas");
+ /** @id MochiKit.DOM.CAPTION */
+ this.CAPTION = createDOMFunc("caption");
+ /** @id MochiKit.DOM.DD */
+ this.DD = createDOMFunc("dd");
+ /** @id MochiKit.DOM.DIV */
+ this.DIV = createDOMFunc("div");
+ /** @id MochiKit.DOM.DL */
+ this.DL = createDOMFunc("dl");
+ /** @id MochiKit.DOM.DT */
+ this.DT = createDOMFunc("dt");
+ /** @id MochiKit.DOM.FIELDSET */
+ this.FIELDSET = createDOMFunc("fieldset");
+ /** @id MochiKit.DOM.FIGURE */
+ this.FIGURE = createDOMFunc("figure");
+ /** @id MochiKit.DOM.FIGCAPTION */
+ this.FIGCAPTION = createDOMFunc("figcaption");
+ /** @id MochiKit.DOM.FOOTER */
+ this.FOOTER = createDOMFunc("footer");
+ /** @id MochiKit.DOM.FORM */
+ this.FORM = createDOMFunc("form");
+ /** @id MochiKit.DOM.H1 */
+ this.H1 = createDOMFunc("h1");
+ /** @id MochiKit.DOM.H2 */
+ this.H2 = createDOMFunc("h2");
+ /** @id MochiKit.DOM.H3 */
+ this.H3 = createDOMFunc("h3");
+ /** @id MochiKit.DOM.H4 */
+ this.H4 = createDOMFunc("h4");
+ /** @id MochiKit.DOM.H5 */
+ this.H5 = createDOMFunc("h5");
+ /** @id MochiKit.DOM.H6 */
+ this.H6 = createDOMFunc("h6");
+ /** @id MochiKit.DOM.HEADER */
+ this.HEADER = createDOMFunc("header");
+ /** @id MochiKit.DOM.HGROUP */
+ this.HGROUP = createDOMFunc("hgroup");
+ /** @id MochiKit.DOM.HR */
+ this.HR = createDOMFunc("hr");
+ /** @id MochiKit.DOM.IFRAME */
+ this.IFRAME = createDOMFunc("iframe");
+ /** @id MochiKit.DOM.IMG */
+ this.IMG = createDOMFunc("img");
+ /** @id MochiKit.DOM.INPUT */
+ this.INPUT = createDOMFunc("input");
+ /** @id MochiKit.DOM.LABEL */
+ this.LABEL = createDOMFunc("label");
+ /** @id MochiKit.DOM.LEGEND */
+ this.LEGEND = createDOMFunc("legend");
+ /** @id MochiKit.DOM.LI */
+ this.LI = createDOMFunc("li");
+ /** @id MochiKit.DOM.LINK */
+ this.LINK = createDOMFunc("link");
+ /** @id MochiKit.DOM.MARK */
+ this.MARK = createDOMFunc("mark");
+ /** @id MochiKit.DOM.METER */
+ this.METER = createDOMFunc("meter");
+ /** @id MochiKit.DOM.NAV */
+ this.NAV = createDOMFunc("nav");
+ /** @id MochiKit.DOM.OL */
+ this.OL = createDOMFunc("ol");
+ /** @id MochiKit.DOM.OPTGROUP */
+ this.OPTGROUP = createDOMFunc("optgroup");
+ /** @id MochiKit.DOM.OPTION */
+ this.OPTION = createDOMFunc("option");
+ /** @id MochiKit.DOM.P */
+ this.P = createDOMFunc("p");
+ /** @id MochiKit.DOM.PRE */
+ this.PRE = createDOMFunc("pre");
+ /** @id MochiKit.DOM.PROGRESS */
+ this.PROGRESS = createDOMFunc("progress");
+ /** @id MochiKit.DOM.SCRIPT */
+ this.SCRIPT = createDOMFunc("script");
+ /** @id MochiKit.DOM.SECTION */
+ this.SECTION = createDOMFunc("section");
+ /** @id MochiKit.DOM.SELECT */
+ this.SELECT = createDOMFunc("select");
+ /** @id MochiKit.DOM.SPAN */
+ this.SPAN = createDOMFunc("span");
+ /** @id MochiKit.DOM.STRONG */
+ this.STRONG = createDOMFunc("strong");
+ /** @id MochiKit.DOM.STYLE */
+ this.STYLE = createDOMFunc("style");
+ /** @id MochiKit.DOM.TABLE */
+ this.TABLE = createDOMFunc("table");
+ /** @id MochiKit.DOM.TBODY */
+ this.TBODY = createDOMFunc("tbody");
+ /** @id MochiKit.DOM.TD */
+ this.TD = createDOMFunc("td");
+ /** @id MochiKit.DOM.TEXTAREA */
+ this.TEXTAREA = createDOMFunc("textarea");
+ /** @id MochiKit.DOM.TFOOT */
+ this.TFOOT = createDOMFunc("tfoot");
+ /** @id MochiKit.DOM.TH */
+ this.TH = createDOMFunc("th");
+ /** @id MochiKit.DOM.THEAD */
+ this.THEAD = createDOMFunc("thead");
+ /** @id MochiKit.DOM.TR */
+ this.TR = createDOMFunc("tr");
+ /** @id MochiKit.DOM.TT */
+ this.TT = createDOMFunc("tt");
+ /** @id MochiKit.DOM.UL */
+ this.UL = createDOMFunc("ul");
+ /** @id MochiKit.DOM.NBSP */
+ this.NBSP = "\u00a0";
+ /** @id MochiKit.DOM.$ */
+ this.$ = this.getElement;
+
+ m.nameFunctions(this);
+ }
+});
+
+
+MochiKit.DOM.__new__(((typeof(window) == "undefined") ? this : window));
+
+//
+// XXX: Internet Explorer blows
+//
+if (MochiKit.__export__) {
+ withWindow = MochiKit.DOM.withWindow;
+ withDocument = MochiKit.DOM.withDocument;
+}
+
+MochiKit.Base._exportSymbols(this, MochiKit.DOM);
diff --git a/frontend/delta/js/MochiKit/DateTime.js b/frontend/delta/js/MochiKit/DateTime.js
new file mode 100644
index 0000000..24ca087
--- /dev/null
+++ b/frontend/delta/js/MochiKit/DateTime.js
@@ -0,0 +1,199 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.DateTime 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'DateTime', '1.5', ['Base']);
+
+/** @id MochiKit.DateTime.isoDate */
+MochiKit.DateTime.isoDate = function (str) {
+ str = str + "";
+ if (typeof(str) != "string" || str.length === 0) {
+ return null;
+ }
+ var iso = str.split('-');
+ if (iso.length === 0) {
+ return null;
+ }
+ var date = new Date(parseInt(iso[0], 10), parseInt(iso[1], 10) - 1, parseInt(iso[2], 10));
+ date.setFullYear(iso[0]);
+ date.setMonth(iso[1] - 1);
+ date.setDate(iso[2]);
+ return date;
+};
+
+MochiKit.DateTime._isoRegexp = /(\d{4,})(?:-(\d{1,2})(?:-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?(?:(Z)|([+-])(\d{1,2})(?::(\d{1,2}))?)?)?)?)?/;
+
+/** @id MochiKit.DateTime.isoTimestamp */
+MochiKit.DateTime.isoTimestamp = function (str) {
+ str = str + "";
+ if (typeof(str) != "string" || str.length === 0) {
+ return null;
+ }
+ var res = str.match(MochiKit.DateTime._isoRegexp);
+ if (typeof(res) == "undefined" || res === null) {
+ return null;
+ }
+ var year, month, day, hour, min, sec, msec;
+ year = parseInt(res[1], 10);
+ if (typeof(res[2]) == "undefined" || res[2] === '') {
+ return new Date(year);
+ }
+ month = parseInt(res[2], 10) - 1;
+ day = parseInt(res[3], 10);
+ if (typeof(res[4]) == "undefined" || res[4] === '') {
+ return new Date(year, month, day);
+ }
+ hour = parseInt(res[4], 10);
+ min = parseInt(res[5], 10);
+ sec = (typeof(res[6]) != "undefined" && res[6] !== '') ? parseInt(res[6], 10) : 0;
+ if (typeof(res[7]) != "undefined" && res[7] !== '') {
+ msec = Math.round(1000.0 * parseFloat("0." + res[7]));
+ } else {
+ msec = 0;
+ }
+ if ((typeof(res[8]) == "undefined" || res[8] === '') && (typeof(res[9]) == "undefined" || res[9] === '')) {
+ return new Date(year, month, day, hour, min, sec, msec);
+ }
+ var ofs;
+ if (typeof(res[9]) != "undefined" && res[9] !== '') {
+ ofs = parseInt(res[10], 10) * 3600000;
+ if (typeof(res[11]) != "undefined" && res[11] !== '') {
+ ofs += parseInt(res[11], 10) * 60000;
+ }
+ if (res[9] == "-") {
+ ofs = -ofs;
+ }
+ } else {
+ ofs = 0;
+ }
+ return new Date(Date.UTC(year, month, day, hour, min, sec, msec) - ofs);
+};
+
+/** @id MochiKit.DateTime.toISOTime */
+MochiKit.DateTime.toISOTime = function (date, realISO/* = false */) {
+ if (typeof(date) == "undefined" || date === null) {
+ return null;
+ }
+ var _padTwo = MochiKit.DateTime._padTwo;
+ if (realISO) {
+ // adjust date for UTC timezone
+ date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
+ }
+ var lst = [
+ (realISO ? _padTwo(date.getHours()) : date.getHours()),
+ _padTwo(date.getMinutes()),
+ _padTwo(date.getSeconds())
+ ];
+ return lst.join(":") + (realISO ? "Z" : "");
+};
+
+/** @id MochiKit.DateTime.toISOTimeStamp */
+MochiKit.DateTime.toISOTimestamp = function (date, realISO/* = false*/) {
+ if (typeof(date) == "undefined" || date === null) {
+ return null;
+ }
+ var time = MochiKit.DateTime.toISOTime(date, realISO);
+ var sep = realISO ? "T" : " ";
+ if (realISO) {
+ // adjust date for UTC timezone
+ date = new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
+ }
+ return MochiKit.DateTime.toISODate(date) + sep + time;
+};
+
+/** @id MochiKit.DateTime.toISODate */
+MochiKit.DateTime.toISODate = function (date) {
+ if (typeof(date) == "undefined" || date === null) {
+ return null;
+ }
+ var _padTwo = MochiKit.DateTime._padTwo;
+ var _padFour = MochiKit.DateTime._padFour;
+ return [
+ _padFour(date.getFullYear()),
+ _padTwo(date.getMonth() + 1),
+ _padTwo(date.getDate())
+ ].join("-");
+};
+
+/** @id MochiKit.DateTime.americanDate */
+MochiKit.DateTime.americanDate = function (d) {
+ d = d + "";
+ if (typeof(d) != "string" || d.length === 0) {
+ return null;
+ }
+ var a = d.split('/');
+ return new Date(a[2], a[0] - 1, a[1]);
+};
+
+MochiKit.DateTime._padTwo = function (n) {
+ return (n > 9) ? n : "0" + n;
+};
+
+MochiKit.DateTime._padFour = function(n) {
+ switch(n.toString().length) {
+ case 1: return "000" + n; break;
+ case 2: return "00" + n; break;
+ case 3: return "0" + n; break;
+ case 4:
+ default:
+ return n;
+ }
+};
+
+/** @id MochiKit.DateTime.toPaddedAmericanDate */
+MochiKit.DateTime.toPaddedAmericanDate = function (d) {
+ if (typeof(d) == "undefined" || d === null) {
+ return null;
+ }
+ var _padTwo = MochiKit.DateTime._padTwo;
+ return [
+ _padTwo(d.getMonth() + 1),
+ _padTwo(d.getDate()),
+ d.getFullYear()
+ ].join('/');
+};
+
+/** @id MochiKit.DateTime.toAmericanDate */
+MochiKit.DateTime.toAmericanDate = function (d) {
+ if (typeof(d) == "undefined" || d === null) {
+ return null;
+ }
+ return [d.getMonth() + 1, d.getDate(), d.getFullYear()].join('/');
+};
+
+MochiKit.DateTime.__new__ = function () {
+ MochiKit.Base.nameFunctions(this);
+};
+
+MochiKit.DateTime.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.DateTime);
diff --git a/frontend/delta/js/MochiKit/DragAndDrop.js b/frontend/delta/js/MochiKit/DragAndDrop.js
new file mode 100644
index 0000000..850e6bb
--- /dev/null
+++ b/frontend/delta/js/MochiKit/DragAndDrop.js
@@ -0,0 +1,789 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+MochiKit.DragAndDrop 1.5
+
+See for documentation, downloads, license, etc.
+
+Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+ Mochi-ized By Thomas Herve (_firstname_@nimail.org)
+
+***/
+
+MochiKit.Base.module(MochiKit, 'DragAndDrop', '1.5', ['Base', 'Iter', 'DOM', 'Signal', 'Visual', 'Position']);
+
+MochiKit.DragAndDrop.Droppables = {
+ /***
+
+ Manage all droppables. Shouldn't be used, use the Droppable object instead.
+
+ ***/
+ drops: [],
+
+ remove: function (element) {
+ this.drops = MochiKit.Base.filter(function (d) {
+ return d.element != MochiKit.DOM.getElement(element);
+ }, this.drops);
+ },
+
+ register: function (drop) {
+ this.drops.push(drop);
+ },
+
+ unregister: function (drop) {
+ this.drops = MochiKit.Base.filter(function (d) {
+ return d != drop;
+ }, this.drops);
+ },
+
+ prepare: function (element) {
+ MochiKit.Base.map(function (drop) {
+ if (drop.isAccepted(element)) {
+ if (drop.options.activeclass) {
+ MochiKit.DOM.addElementClass(drop.element,
+ drop.options.activeclass);
+ }
+ drop.options.onactive(drop.element, element);
+ }
+ }, this.drops);
+ },
+
+ findDeepestChild: function (drops) {
+ var deepest = drops[0];
+
+ for (var i = 1; i < drops.length; ++i) {
+ if (MochiKit.DOM.isChildNode(drops[i].element, deepest.element)) {
+ deepest = drops[i];
+ }
+ }
+ return deepest;
+ },
+
+ show: function (point, element) {
+ if (!this.drops.length) {
+ return;
+ }
+ var affected = [];
+
+ if (this.last_active) {
+ this.last_active.deactivate();
+ }
+ MochiKit.Iter.forEach(this.drops, function (drop) {
+ if (drop.isAffected(point, element)) {
+ affected.push(drop);
+ }
+ });
+ if (affected.length > 0) {
+ var drop = this.findDeepestChild(affected);
+ MochiKit.Position.within(drop.element, point.page.x, point.page.y);
+ drop.options.onhover(element, drop.element,
+ MochiKit.Position.overlap(drop.options.overlap, drop.element));
+ drop.activate();
+ }
+ },
+
+ fire: function (event, element) {
+ if (!this.last_active) {
+ return;
+ }
+ MochiKit.Position.prepare();
+
+ if (this.last_active.isAffected(event.mouse(), element)) {
+ this.last_active.options.ondrop(element,
+ this.last_active.element, event);
+ }
+ },
+
+ reset: function (element) {
+ MochiKit.Base.map(function (drop) {
+ if (drop.options.activeclass) {
+ MochiKit.DOM.removeElementClass(drop.element,
+ drop.options.activeclass);
+ }
+ drop.options.ondesactive(drop.element, element);
+ }, this.drops);
+ if (this.last_active) {
+ this.last_active.deactivate();
+ }
+ }
+};
+
+/** @id MochiKit.DragAndDrop.Droppable */
+MochiKit.DragAndDrop.Droppable = function (element, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, options);
+ }
+ this.__init__(element, options);
+};
+
+MochiKit.DragAndDrop.Droppable.prototype = {
+ /***
+
+ A droppable object. Simple use is to create giving an element:
+
+ new MochiKit.DragAndDrop.Droppable('myelement');
+
+ Generally you'll want to define the 'ondrop' function and maybe the
+ 'accept' option to filter draggables.
+
+ ***/
+ __class__: MochiKit.DragAndDrop.Droppable,
+
+ __init__: function (element, /* optional */options) {
+ var d = MochiKit.DOM;
+ var b = MochiKit.Base;
+ this.element = d.getElement(element);
+ this.options = b.update({
+
+ /** @id MochiKit.DragAndDrop.greedy */
+ greedy: true,
+
+ /** @id MochiKit.DragAndDrop.hoverclass */
+ hoverclass: null,
+
+ /** @id MochiKit.DragAndDrop.activeclass */
+ activeclass: null,
+
+ /** @id MochiKit.DragAndDrop.hoverfunc */
+ hoverfunc: b.noop,
+
+ /** @id MochiKit.DragAndDrop.accept */
+ accept: null,
+
+ /** @id MochiKit.DragAndDrop.onactive */
+ onactive: b.noop,
+
+ /** @id MochiKit.DragAndDrop.ondesactive */
+ ondesactive: b.noop,
+
+ /** @id MochiKit.DragAndDrop.onhover */
+ onhover: b.noop,
+
+ /** @id MochiKit.DragAndDrop.ondrop */
+ ondrop: b.noop,
+
+ /** @id MochiKit.DragAndDrop.containment */
+ containment: [],
+ tree: false
+ }, options);
+
+ // cache containers
+ this.options._containers = [];
+ b.map(MochiKit.Base.bind(function (c) {
+ this.options._containers.push(d.getElement(c));
+ }, this), this.options.containment);
+
+ MochiKit.Style.makePositioned(this.element); // fix IE
+
+ MochiKit.DragAndDrop.Droppables.register(this);
+ },
+
+ /** @id MochiKit.DragAndDrop.isContained */
+ isContained: function (element) {
+ if (this.options._containers.length) {
+ var containmentNode;
+ if (this.options.tree) {
+ containmentNode = element.treeNode;
+ } else {
+ containmentNode = element.parentNode;
+ }
+ return MochiKit.Iter.some(this.options._containers, function (c) {
+ return containmentNode == c;
+ });
+ } else {
+ return true;
+ }
+ },
+
+ /** @id MochiKit.DragAndDrop.isAccepted */
+ isAccepted: function (element) {
+ return ((!this.options.accept) || MochiKit.Iter.some(
+ this.options.accept, function (c) {
+ return MochiKit.DOM.hasElementClass(element, c);
+ }));
+ },
+
+ /** @id MochiKit.DragAndDrop.isAffected */
+ isAffected: function (point, element) {
+ return ((this.element != element) &&
+ this.isContained(element) &&
+ this.isAccepted(element) &&
+ MochiKit.Position.within(this.element, point.page.x,
+ point.page.y));
+ },
+
+ /** @id MochiKit.DragAndDrop.deactivate */
+ deactivate: function () {
+ /***
+
+ A droppable is deactivate when a draggable has been over it and left.
+
+ ***/
+ if (this.options.hoverclass) {
+ MochiKit.DOM.removeElementClass(this.element,
+ this.options.hoverclass);
+ }
+ this.options.hoverfunc(this.element, false);
+ MochiKit.DragAndDrop.Droppables.last_active = null;
+ },
+
+ /** @id MochiKit.DragAndDrop.activate */
+ activate: function () {
+ /***
+
+ A droppable is active when a draggable is over it.
+
+ ***/
+ if (this.options.hoverclass) {
+ MochiKit.DOM.addElementClass(this.element, this.options.hoverclass);
+ }
+ this.options.hoverfunc(this.element, true);
+ MochiKit.DragAndDrop.Droppables.last_active = this;
+ },
+
+ /** @id MochiKit.DragAndDrop.destroy */
+ destroy: function () {
+ /***
+
+ Delete this droppable.
+
+ ***/
+ MochiKit.DragAndDrop.Droppables.unregister(this);
+ },
+
+ /** @id MochiKit.DragAndDrop.repr */
+ repr: function () {
+ return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
+ }
+};
+
+MochiKit.DragAndDrop.Draggables = {
+ /***
+
+ Manage draggables elements. Not intended to direct use.
+
+ ***/
+ drags: [],
+
+ register: function (draggable) {
+ if (this.drags.length === 0) {
+ var conn = MochiKit.Signal.connect;
+ this.eventMouseUp = conn(document, 'onmouseup', this, this.endDrag);
+ this.eventMouseMove = conn(document, 'onmousemove', this,
+ this.updateDrag);
+ this.eventKeypress = conn(document, 'onkeypress', this,
+ this.keyPress);
+ }
+ this.drags.push(draggable);
+ },
+
+ unregister: function (draggable) {
+ this.drags = MochiKit.Base.filter(function (d) {
+ return d != draggable;
+ }, this.drags);
+ if (this.drags.length === 0) {
+ var disc = MochiKit.Signal.disconnect;
+ disc(this.eventMouseUp);
+ disc(this.eventMouseMove);
+ disc(this.eventKeypress);
+ }
+ },
+
+ activate: function (draggable) {
+ // allows keypress events if window is not currently focused
+ // fails for Safari
+ window.focus();
+ this.activeDraggable = draggable;
+ },
+
+ deactivate: function () {
+ this.activeDraggable = null;
+ },
+
+ updateDrag: function (event) {
+ if (!this.activeDraggable) {
+ return;
+ }
+ var pointer = event.mouse();
+ // Mozilla-based browsers fire successive mousemove events with
+ // the same coordinates, prevent needless redrawing (moz bug?)
+ if (this._lastPointer &&
+ this._lastPointer.page.x == pointer.page.x &&
+ this._lastPointer.page.y == pointer.page.y) {
+ return;
+ }
+ this._lastPointer = pointer;
+ this.activeDraggable.updateDrag(event, pointer);
+ },
+
+ endDrag: function (event) {
+ if (!this.activeDraggable) {
+ return;
+ }
+ this._lastPointer = null;
+ this.activeDraggable.endDrag(event);
+ this.activeDraggable = null;
+ },
+
+ keyPress: function (event) {
+ if (this.activeDraggable) {
+ this.activeDraggable.keyPress(event);
+ }
+ },
+
+ notify: function (eventName, draggable, event) {
+ MochiKit.Signal.signal(this, eventName, draggable, event);
+ }
+};
+
+/** @id MochiKit.DragAndDrop.Draggable */
+MochiKit.DragAndDrop.Draggable = function (element, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, options);
+ }
+ this.__init__(element, options);
+};
+
+MochiKit.DragAndDrop.Draggable.prototype = {
+ /***
+
+ A draggable object. Simple instantiate :
+
+ new MochiKit.DragAndDrop.Draggable('myelement');
+
+ ***/
+ __class__ : MochiKit.DragAndDrop.Draggable,
+
+ __init__: function (element, /* optional */options) {
+ var v = MochiKit.Visual;
+ var b = MochiKit.Base;
+ options = b.update({
+
+ /** @id MochiKit.DragAndDrop.handle */
+ handle: false,
+
+ /** @id MochiKit.DragAndDrop.starteffect */
+ starteffect: function (innerelement) {
+ this._savedOpacity = MochiKit.Style.getStyle(innerelement, 'opacity') || 1.0;
+ new v.Opacity(innerelement, {duration:0.2, from:this._savedOpacity, to:0.7});
+ },
+ /** @id MochiKit.DragAndDrop.reverteffect */
+ reverteffect: function (innerelement, top_offset, left_offset) {
+ var dur = Math.sqrt(Math.abs(top_offset^2) +
+ Math.abs(left_offset^2))*0.02;
+ return new v.Move(innerelement,
+ {x: -left_offset, y: -top_offset, duration: dur});
+ },
+
+ /** @id MochiKit.DragAndDrop.endeffect */
+ endeffect: function (innerelement) {
+ new v.Opacity(innerelement, {duration:0.2, from:0.7, to:this._savedOpacity});
+ },
+
+ /** @id MochiKit.DragAndDrop.onchange */
+ onchange: b.noop,
+
+ /** @id MochiKit.DragAndDrop.zindex */
+ zindex: 1000,
+
+ /** @id MochiKit.DragAndDrop.revert */
+ revert: false,
+
+ /** @id MochiKit.DragAndDrop.scroll */
+ scroll: false,
+
+ /** @id MochiKit.DragAndDrop.scrollSensitivity */
+ scrollSensitivity: 20,
+
+ /** @id MochiKit.DragAndDrop.scrollSpeed */
+ scrollSpeed: 15,
+ // false, or xy or [x, y] or function (x, y){return [x, y];}
+
+ /** @id MochiKit.DragAndDrop.snap */
+ snap: false
+ }, options);
+
+ var d = MochiKit.DOM;
+ this.element = d.getElement(element);
+
+ if (options.handle && (typeof(options.handle) == 'string')) {
+ this.handle = d.getFirstElementByTagAndClassName(null,
+ options.handle, this.element);
+ }
+ if (!this.handle) {
+ this.handle = d.getElement(options.handle);
+ }
+ if (!this.handle) {
+ this.handle = this.element;
+ }
+
+ if (options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
+ options.scroll = d.getElement(options.scroll);
+ this._isScrollChild = MochiKit.DOM.isChildNode(this.element, options.scroll);
+ }
+
+ MochiKit.Style.makePositioned(this.element); // fix IE
+
+ this.delta = this.currentDelta();
+ this.options = options;
+ this.dragging = false;
+
+ this.eventMouseDown = MochiKit.Signal.connect(this.handle,
+ 'onmousedown', this, this.initDrag);
+ MochiKit.DragAndDrop.Draggables.register(this);
+ },
+
+ /** @id MochiKit.DragAndDrop.destroy */
+ destroy: function () {
+ MochiKit.Signal.disconnect(this.eventMouseDown);
+ MochiKit.DragAndDrop.Draggables.unregister(this);
+ },
+
+ /** @id MochiKit.DragAndDrop.currentDelta */
+ currentDelta: function () {
+ var s = MochiKit.Style.getStyle;
+ return [
+ parseInt(s(this.element, 'left') || '0', 10),
+ parseInt(s(this.element, 'top') || '0', 10)];
+ },
+
+ /** @id MochiKit.DragAndDrop.initDrag */
+ initDrag: function (event) {
+ if (!event.mouse().button.left) {
+ return;
+ }
+ // abort on form elements, fixes a Firefox issue
+ var src = event.target();
+ var tagName = (src.tagName || '').toUpperCase();
+ if (tagName === 'INPUT' || tagName === 'SELECT' ||
+ tagName === 'OPTION' || tagName === 'BUTTON' ||
+ tagName === 'TEXTAREA') {
+ return;
+ }
+
+ if (this._revert) {
+ this._revert.cancel();
+ this._revert = null;
+ }
+
+ var pointer = event.mouse();
+ var pos = MochiKit.Position.cumulativeOffset(this.element);
+ this.offset = [pointer.page.x - pos.x, pointer.page.y - pos.y];
+
+ MochiKit.DragAndDrop.Draggables.activate(this);
+ event.stop();
+ },
+
+ /** @id MochiKit.DragAndDrop.startDrag */
+ startDrag: function (event) {
+ this.dragging = true;
+ if (this.options.selectclass) {
+ MochiKit.DOM.addElementClass(this.element,
+ this.options.selectclass);
+ }
+ if (this.options.zindex) {
+ this.originalZ = MochiKit.Style.getStyle(this.element, 'z-index');
+ this.element.style.zIndex = this.options.zindex;
+ }
+
+ if (this.options.ghosting) {
+ this._clone = this.element.cloneNode(true);
+ this.ghostPosition = MochiKit.Position.absolutize(this.element);
+ this.element.parentNode.insertBefore(this._clone, this.element);
+ }
+
+ if (this.options.scroll) {
+ if (this.options.scroll == window) {
+ var where = this._getWindowScroll(this.options.scroll);
+ this.originalScrollLeft = where.left;
+ this.originalScrollTop = where.top;
+ } else {
+ this.originalScrollLeft = this.options.scroll.scrollLeft;
+ this.originalScrollTop = this.options.scroll.scrollTop;
+ }
+ }
+
+ MochiKit.DragAndDrop.Droppables.prepare(this.element);
+ MochiKit.DragAndDrop.Draggables.notify('start', this, event);
+ if (this.options.starteffect) {
+ this.options.starteffect(this.element);
+ }
+ },
+
+ /** @id MochiKit.DragAndDrop.updateDrag */
+ updateDrag: function (event, pointer) {
+ if (!this.dragging) {
+ this.startDrag(event);
+ }
+ MochiKit.Position.prepare();
+ MochiKit.DragAndDrop.Droppables.show(pointer, this.element);
+ MochiKit.DragAndDrop.Draggables.notify('drag', this, event);
+ this.draw(pointer);
+ this.options.onchange(this);
+
+ if (this.options.scroll) {
+ this.stopScrolling();
+ var p, q;
+ if (this.options.scroll == window) {
+ var s = this._getWindowScroll(this.options.scroll);
+ p = new MochiKit.Style.Coordinates(s.left, s.top);
+ q = new MochiKit.Style.Coordinates(s.left + s.width,
+ s.top + s.height);
+ } else {
+ p = MochiKit.Position.page(this.options.scroll);
+ p.x += this.options.scroll.scrollLeft;
+ p.y += this.options.scroll.scrollTop;
+ p.x += (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0);
+ p.y += (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0);
+ q = new MochiKit.Style.Coordinates(p.x + this.options.scroll.offsetWidth,
+ p.y + this.options.scroll.offsetHeight);
+ }
+ var speed = [0, 0];
+ if (pointer.page.x > (q.x - this.options.scrollSensitivity)) {
+ speed[0] = pointer.page.x - (q.x - this.options.scrollSensitivity);
+ } else if (pointer.page.x < (p.x + this.options.scrollSensitivity)) {
+ speed[0] = pointer.page.x - (p.x + this.options.scrollSensitivity);
+ }
+ if (pointer.page.y > (q.y - this.options.scrollSensitivity)) {
+ speed[1] = pointer.page.y - (q.y - this.options.scrollSensitivity);
+ } else if (pointer.page.y < (p.y + this.options.scrollSensitivity)) {
+ speed[1] = pointer.page.y - (p.y + this.options.scrollSensitivity);
+ }
+ this.startScrolling(speed);
+ }
+
+ // fix AppleWebKit rendering
+ if (/AppleWebKit/.test(navigator.appVersion)) {
+ window.scrollBy(0, 0);
+ }
+ event.stop();
+ },
+
+ /** @id MochiKit.DragAndDrop.finishDrag */
+ finishDrag: function (event, success) {
+ var dr = MochiKit.DragAndDrop;
+ this.dragging = false;
+ if (this.options.selectclass) {
+ MochiKit.DOM.removeElementClass(this.element,
+ this.options.selectclass);
+ }
+
+ if (this.options.ghosting) {
+ // XXX: from a user point of view, it would be better to remove
+ // the node only *after* the MochiKit.Visual.Move end when used
+ // with revert.
+ MochiKit.Position.relativize(this.element, this.ghostPosition);
+ MochiKit.DOM.removeElement(this._clone);
+ this._clone = null;
+ }
+
+ if (success) {
+ dr.Droppables.fire(event, this.element);
+ }
+ dr.Draggables.notify('end', this, event);
+
+ var revert = this.options.revert;
+ if (revert && typeof(revert) == 'function') {
+ revert = revert(this.element);
+ }
+
+ var d = this.currentDelta();
+ if (revert && this.options.reverteffect) {
+ this._revert = this.options.reverteffect(this.element,
+ d[1] - this.delta[1], d[0] - this.delta[0]);
+ } else {
+ this.delta = d;
+ }
+
+ if (this.options.zindex) {
+ this.element.style.zIndex = this.originalZ;
+ }
+
+ if (this.options.endeffect) {
+ this.options.endeffect(this.element);
+ }
+
+ dr.Draggables.deactivate();
+ dr.Droppables.reset(this.element);
+ },
+
+ /** @id MochiKit.DragAndDrop.keyPress */
+ keyPress: function (event) {
+ if (event.key().string != "KEY_ESCAPE") {
+ return;
+ }
+ this.finishDrag(event, false);
+ event.stop();
+ },
+
+ /** @id MochiKit.DragAndDrop.endDrag */
+ endDrag: function (event) {
+ if (!this.dragging) {
+ return;
+ }
+ this.stopScrolling();
+ this.finishDrag(event, true);
+ event.stop();
+ },
+
+ /** @id MochiKit.DragAndDrop.draw */
+ draw: function (point) {
+ var pos = MochiKit.Position.cumulativeOffset(this.element);
+ var d = this.currentDelta();
+ pos.x -= d[0];
+ pos.y -= d[1];
+
+ if (this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
+ pos.x -= this.options.scroll.scrollLeft - this.originalScrollLeft;
+ pos.y -= this.options.scroll.scrollTop - this.originalScrollTop;
+ }
+
+ var p = [point.page.x - pos.x - this.offset[0],
+ point.page.y - pos.y - this.offset[1]];
+
+ if (this.options.snap) {
+ if (typeof(this.options.snap) == 'function') {
+ p = this.options.snap(p[0], p[1]);
+ } else {
+ if (this.options.snap instanceof Array) {
+ var i = -1;
+ p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
+ i += 1;
+ return Math.round(v/this.options.snap[i]) *
+ this.options.snap[i];
+ }, this), p);
+ } else {
+ p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
+ return Math.round(v/this.options.snap) *
+ this.options.snap;
+ }, this), p);
+ }
+ }
+ }
+ var style = this.element.style;
+ if ((!this.options.constraint) ||
+ (this.options.constraint == 'horizontal')) {
+ style.left = p[0] + 'px';
+ }
+ if ((!this.options.constraint) ||
+ (this.options.constraint == 'vertical')) {
+ style.top = p[1] + 'px';
+ }
+ if (style.visibility == 'hidden') {
+ style.visibility = ''; // fix gecko rendering
+ }
+ },
+
+ /** @id MochiKit.DragAndDrop.stopScrolling */
+ stopScrolling: function () {
+ if (this.scrollInterval) {
+ clearInterval(this.scrollInterval);
+ this.scrollInterval = null;
+ MochiKit.DragAndDrop.Draggables._lastScrollPointer = null;
+ }
+ },
+
+ /** @id MochiKit.DragAndDrop.startScrolling */
+ startScrolling: function (speed) {
+ if (!speed[0] && !speed[1]) {
+ return;
+ }
+ this.scrollSpeed = [speed[0] * this.options.scrollSpeed,
+ speed[1] * this.options.scrollSpeed];
+ this.lastScrolled = new Date();
+ this.scrollInterval = setInterval(MochiKit.Base.bind(this.scroll, this), 10);
+ },
+
+ /** @id MochiKit.DragAndDrop.scroll */
+ scroll: function () {
+ var current = new Date();
+ var delta = current - this.lastScrolled;
+ this.lastScrolled = current;
+
+ if (this.options.scroll == window) {
+ var s = this._getWindowScroll(this.options.scroll);
+ if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
+ var dm = delta / 1000;
+ this.options.scroll.scrollTo(s.left + dm * this.scrollSpeed[0],
+ s.top + dm * this.scrollSpeed[1]);
+ }
+ } else {
+ this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
+ this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
+ }
+
+ var d = MochiKit.DragAndDrop;
+
+ MochiKit.Position.prepare();
+ d.Droppables.show(d.Draggables._lastPointer, this.element);
+ d.Draggables.notify('drag', this);
+ if (this._isScrollChild) {
+ d.Draggables._lastScrollPointer = d.Draggables._lastScrollPointer || d.Draggables._lastPointer;
+ d.Draggables._lastScrollPointer.x += this.scrollSpeed[0] * delta / 1000;
+ d.Draggables._lastScrollPointer.y += this.scrollSpeed[1] * delta / 1000;
+ if (d.Draggables._lastScrollPointer.x < 0) {
+ d.Draggables._lastScrollPointer.x = 0;
+ }
+ if (d.Draggables._lastScrollPointer.y < 0) {
+ d.Draggables._lastScrollPointer.y = 0;
+ }
+ this.draw(d.Draggables._lastScrollPointer);
+ }
+
+ this.options.onchange(this);
+ },
+
+ _getWindowScroll: function (win) {
+ var vp, w, h;
+ MochiKit.DOM.withWindow(win, function () {
+ vp = MochiKit.Style.getViewportPosition(win.document);
+ });
+ if (win.innerWidth) {
+ w = win.innerWidth;
+ h = win.innerHeight;
+ } else if (win.document.documentElement && win.document.documentElement.clientWidth) {
+ w = win.document.documentElement.clientWidth;
+ h = win.document.documentElement.clientHeight;
+ } else {
+ w = win.document.body.offsetWidth;
+ h = win.document.body.offsetHeight;
+ }
+ return {top: vp.y, left: vp.x, width: w, height: h};
+ },
+
+ /** @id MochiKit.DragAndDrop.repr */
+ repr: function () {
+ return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
+ }
+};
+
+MochiKit.DragAndDrop.__new__ = function () {
+ MochiKit.Base.nameFunctions(this);
+};
+
+MochiKit.DragAndDrop.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.DragAndDrop);
diff --git a/frontend/delta/js/MochiKit/Format.js b/frontend/delta/js/MochiKit/Format.js
new file mode 100644
index 0000000..0e7af50
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Format.js
@@ -0,0 +1,332 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Format 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Format', '1.5', ['Base']);
+
+MochiKit.Format._numberFormatter = function (placeholder, header, footer, locale, isPercent, precision, leadingZeros, separatorAt, trailingZeros) {
+ return function (num) {
+ num = parseFloat(num);
+ if (typeof(num) == "undefined" || num === null || isNaN(num)) {
+ return placeholder;
+ }
+ var curheader = header;
+ var curfooter = footer;
+ if (num < 0) {
+ num = -num;
+ } else {
+ curheader = curheader.replace(/-/, "");
+ }
+ var me = arguments.callee;
+ var fmt = MochiKit.Format.formatLocale(locale);
+ if (isPercent) {
+ num = num * 100.0;
+ curfooter = fmt.percent + curfooter;
+ }
+ num = MochiKit.Format.roundToFixed(num, precision);
+ var parts = num.split(/\./);
+ var whole = parts[0];
+ var frac = (parts.length == 1) ? "" : parts[1];
+ var res = "";
+ while (whole.length < leadingZeros) {
+ whole = "0" + whole;
+ }
+ if (separatorAt) {
+ while (whole.length > separatorAt) {
+ var i = whole.length - separatorAt;
+ //res = res + fmt.separator + whole.substring(i, whole.length);
+ res = fmt.separator + whole.substring(i, whole.length) + res;
+ whole = whole.substring(0, i);
+ }
+ }
+ res = whole + res;
+ if (precision > 0) {
+ while (frac.length < trailingZeros) {
+ frac = frac + "0";
+ }
+ res = res + fmt.decimal + frac;
+ }
+ return curheader + res + curfooter;
+ };
+};
+
+/** @id MochiKit.Format.numberFormatter */
+MochiKit.Format.numberFormatter = function (pattern, placeholder/* = "" */, locale/* = "default" */) {
+ // http://java.sun.com/docs/books/tutorial/i18n/format/numberpattern.html
+ // | 0 | leading or trailing zeros
+ // | # | just the number
+ // | , | separator
+ // | . | decimal separator
+ // | % | Multiply by 100 and format as percent
+ if (typeof(placeholder) == "undefined") {
+ placeholder = "";
+ }
+ var match = pattern.match(/((?:[0#]+,)?[0#]+)(?:\.([0#]+))?(%)?/);
+ if (!match) {
+ throw TypeError("Invalid pattern");
+ }
+ var header = pattern.substr(0, match.index);
+ var footer = pattern.substr(match.index + match[0].length);
+ if (header.search(/-/) == -1) {
+ header = header + "-";
+ }
+ var whole = match[1];
+ var frac = (typeof(match[2]) == "string" && match[2] != "") ? match[2] : "";
+ var isPercent = (typeof(match[3]) == "string" && match[3] != "");
+ var tmp = whole.split(/,/);
+ var separatorAt;
+ if (typeof(locale) == "undefined") {
+ locale = "default";
+ }
+ if (tmp.length == 1) {
+ separatorAt = null;
+ } else {
+ separatorAt = tmp[1].length;
+ }
+ var leadingZeros = whole.length - whole.replace(/0/g, "").length;
+ var trailingZeros = frac.length - frac.replace(/0/g, "").length;
+ var precision = frac.length;
+ var rval = MochiKit.Format._numberFormatter(
+ placeholder, header, footer, locale, isPercent, precision,
+ leadingZeros, separatorAt, trailingZeros
+ );
+ var m = MochiKit.Base;
+ if (m) {
+ var fn = arguments.callee;
+ var args = m.concat(arguments);
+ rval.repr = function () {
+ return [
+ self.NAME,
+ "(",
+ m.map(m.repr, args).join(", "),
+ ")"
+ ].join("");
+ };
+ }
+ return rval;
+};
+
+/** @id MochiKit.Format.formatLocale */
+MochiKit.Format.formatLocale = function (locale) {
+ if (typeof(locale) == "undefined" || locale === null) {
+ locale = "default";
+ }
+ if (typeof(locale) == "string") {
+ var rval = MochiKit.Format.LOCALE[locale];
+ if (typeof(rval) == "string") {
+ rval = arguments.callee(rval);
+ MochiKit.Format.LOCALE[locale] = rval;
+ }
+ return rval;
+ } else {
+ return locale;
+ }
+};
+
+/** @id MochiKit.Format.twoDigitAverage */
+MochiKit.Format.twoDigitAverage = function (numerator, denominator) {
+ if (denominator) {
+ var res = numerator / denominator;
+ if (!isNaN(res)) {
+ return MochiKit.Format.twoDigitFloat(res);
+ }
+ }
+ return "0";
+};
+
+/** @id MochiKit.Format.twoDigitFloat */
+MochiKit.Format.twoDigitFloat = function (aNumber) {
+ var res = MochiKit.Format.roundToFixed(aNumber, 2);
+ if (res.indexOf(".00") > 0) {
+ return res.substring(0, res.length - 3);
+ } else if (res.charAt(res.length - 1) == "0") {
+ return res.substring(0, res.length - 1);
+ } else {
+ return res;
+ }
+};
+
+/** @id MochiKit.Format.lstrip */
+MochiKit.Format.lstrip = function (str, /* optional */chars) {
+ str = str + "";
+ if (typeof(str) != "string") {
+ return null;
+ }
+ if (!chars) {
+ return str.replace(/^\s+/, "");
+ } else {
+ return str.replace(new RegExp("^[" + chars + "]+"), "");
+ }
+};
+
+/** @id MochiKit.Format.rstrip */
+MochiKit.Format.rstrip = function (str, /* optional */chars) {
+ str = str + "";
+ if (typeof(str) != "string") {
+ return null;
+ }
+ if (!chars) {
+ return str.replace(/\s+$/, "");
+ } else {
+ return str.replace(new RegExp("[" + chars + "]+$"), "");
+ }
+};
+
+/** @id MochiKit.Format.strip */
+MochiKit.Format.strip = function (str, /* optional */chars) {
+ var self = MochiKit.Format;
+ return self.rstrip(self.lstrip(str, chars), chars);
+};
+
+/** @id MochiKit.Format.truncToFixed */
+MochiKit.Format.truncToFixed = function (aNumber, precision) {
+ var fixed = MochiKit.Format._numberToFixed(aNumber, precision);
+ var fracPos = fixed.indexOf(".");
+ if (fracPos > 0 && fracPos + precision + 1 < fixed.length) {
+ fixed = fixed.substring(0, fracPos + precision + 1);
+ fixed = MochiKit.Format._shiftNumber(fixed, 0);
+ }
+ return fixed;
+};
+
+/** @id MochiKit.Format.roundToFixed */
+MochiKit.Format.roundToFixed = function (aNumber, precision) {
+ var fixed = MochiKit.Format._numberToFixed(aNumber, precision);
+ var fracPos = fixed.indexOf(".");
+ if (fracPos > 0 && fracPos + precision + 1 < fixed.length) {
+ var str = MochiKit.Format._shiftNumber(fixed, precision);
+ str = MochiKit.Format._numberToFixed(Math.round(parseFloat(str)), 0);
+ fixed = MochiKit.Format._shiftNumber(str, -precision);
+ }
+ return fixed;
+};
+
+/**
+ * Converts a number to a fixed format string. This function handles
+ * conversion of exponents by shifting the decimal point to the left
+ * or the right. It also guarantees a specified minimum number of
+ * fractional digits (but no maximum).
+ *
+ * @param {Number} aNumber the number to convert
+ * @param {Number} precision the minimum number of decimal digits
+ *
+ * @return {String} the fixed format number string
+ */
+MochiKit.Format._numberToFixed = function (aNumber, precision) {
+ var str = aNumber.toString();
+ var parts = str.split(/[eE]/);
+ var exp = (parts.length === 1) ? 0 : parseInt(parts[1], 10) || 0;
+ var fixed = MochiKit.Format._shiftNumber(parts[0], exp);
+ parts = fixed.split(/\./);
+ var whole = parts[0];
+ var frac = (parts.length === 1) ? "" : parts[1];
+ while (frac.length < precision) {
+ frac += "0";
+ }
+ if (frac.length > 0) {
+ return whole + "." + frac;
+ } else {
+ return whole;
+ }
+};
+
+/**
+ * Shifts the decimal dot location in a fixed format number string.
+ * This function handles negative values and will add and remove
+ * leading and trailing zeros as needed.
+ *
+ * @param {String} num the fixed format number string
+ * @param {Number} exp the base-10 exponent to apply
+ *
+ * @return {String} the new fixed format number string
+ */
+MochiKit.Format._shiftNumber = function (num, exp) {
+ var pos = num.indexOf(".");
+ if (pos < 0) {
+ pos = num.length;
+ } else {
+ num = num.substring(0, pos) + num.substring(pos + 1);
+ }
+ pos += exp;
+ while (pos <= 0 || (pos <= 1 && num.charAt(0) === "-")) {
+ if (num.charAt(0) === "-") {
+ num = "-0" + num.substring(1);
+ } else {
+ num = "0" + num;
+ }
+ pos++;
+ }
+ while (pos > num.length) {
+ num += "0";
+ }
+ if (pos < num.length) {
+ num = num.substring(0, pos) + "." + num.substring(pos);
+ }
+ while (/^0[^.]/.test(num)) {
+ num = num.substring(1);
+ }
+ while (/^-0[^.]/.test(num)) {
+ num = "-" + num.substring(2);
+ }
+ return num;
+};
+
+/** @id MochiKit.Format.percentFormat */
+MochiKit.Format.percentFormat = function (aNumber) {
+ return MochiKit.Format.twoDigitFloat(100 * aNumber) + '%';
+};
+
+MochiKit.Format.LOCALE = {
+ en_US: {separator: ",", decimal: ".", percent: "%"},
+ de_DE: {separator: ".", decimal: ",", percent: "%"},
+ pt_BR: {separator: ".", decimal: ",", percent: "%"},
+ fr_FR: {separator: " ", decimal: ",", percent: "%"},
+ "default": "en_US",
+ __export__: false
+};
+
+MochiKit.Format.__new__ = function () {
+ MochiKit.Base.nameFunctions(this);
+ var base = this.NAME + ".";
+ var k, v, o;
+ for (k in this.LOCALE) {
+ o = this.LOCALE[k];
+ if (typeof(o) == "object") {
+ o.repr = function () { return this.NAME; };
+ o.NAME = base + "LOCALE." + k;
+ }
+ }
+};
+
+MochiKit.Format.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.Format);
diff --git a/frontend/delta/js/MochiKit/Iter.js b/frontend/delta/js/MochiKit/Iter.js
new file mode 100644
index 0000000..8f7ea3d
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Iter.js
@@ -0,0 +1,811 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Iter 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Iter', '1.5', ['Base']);
+
+MochiKit.Base.update(MochiKit.Iter, {
+ /** @id MochiKit.Iter.registerIteratorFactory */
+ registerIteratorFactory: function (name, check, iterfactory, /* optional */ override) {
+ MochiKit.Iter.iteratorRegistry.register(name, check, iterfactory, override);
+ },
+
+ /** @id MochiKit.Iter.isIterable */
+ isIterable: function(o) {
+ return o != null &&
+ (typeof(o.next) == "function" || typeof(o.iter) == "function");
+ },
+
+ /** @id MochiKit.Iter.iter */
+ iter: function (iterable, /* optional */ sentinel) {
+ var self = MochiKit.Iter;
+ if (arguments.length == 2) {
+ return self.takewhile(
+ function (a) { return a != sentinel; },
+ iterable
+ );
+ }
+ if (typeof(iterable.next) == 'function') {
+ return iterable;
+ } else if (typeof(iterable.iter) == 'function') {
+ return iterable.iter();
+ /*
+ } else if (typeof(iterable.__iterator__) == 'function') {
+ //
+ // XXX: We can't support JavaScript 1.7 __iterator__ directly
+ // because of Object.prototype.__iterator__
+ //
+ return iterable.__iterator__();
+ */
+ }
+
+ try {
+ return self.iteratorRegistry.match(iterable);
+ } catch (e) {
+ var m = MochiKit.Base;
+ if (e == m.NotFound) {
+ e = new TypeError(typeof(iterable) + ": " + m.repr(iterable) + " is not iterable");
+ }
+ throw e;
+ }
+ },
+
+ /** @id MochiKit.Iter.count */
+ count: function (n) {
+ if (!n) {
+ n = 0;
+ }
+ var m = MochiKit.Base;
+ return {
+ repr: function () { return "count(" + n + ")"; },
+ toString: m.forwardCall("repr"),
+ next: m.counter(n)
+ };
+ },
+
+ /** @id MochiKit.Iter.cycle */
+ cycle: function (p) {
+ var self = MochiKit.Iter;
+ var m = MochiKit.Base;
+ var lst = [];
+ var iterator = self.iter(p);
+ return {
+ repr: function () { return "cycle(...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ try {
+ var rval = iterator.next();
+ lst.push(rval);
+ return rval;
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ if (lst.length === 0) {
+ this.next = function () {
+ throw self.StopIteration;
+ };
+ } else {
+ var i = -1;
+ this.next = function () {
+ i = (i + 1) % lst.length;
+ return lst[i];
+ };
+ }
+ return this.next();
+ }
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.repeat */
+ repeat: function (elem, /* optional */n) {
+ var m = MochiKit.Base;
+ if (typeof(n) == 'undefined') {
+ return {
+ repr: function () {
+ return "repeat(" + m.repr(elem) + ")";
+ },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ return elem;
+ }
+ };
+ }
+ return {
+ repr: function () {
+ return "repeat(" + m.repr(elem) + ", " + n + ")";
+ },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ if (n <= 0) {
+ throw MochiKit.Iter.StopIteration;
+ }
+ n -= 1;
+ return elem;
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.next */
+ next: function (iterator) {
+ return iterator.next();
+ },
+
+ /** @id MochiKit.Iter.izip */
+ izip: function (p, q/*, ...*/) {
+ var m = MochiKit.Base;
+ var self = MochiKit.Iter;
+ var next = self.next;
+ var iterables = m.map(self.iter, arguments);
+ return {
+ repr: function () { return "izip(...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () { return m.map(next, iterables); }
+ };
+ },
+
+ /** @id MochiKit.Iter.ifilter */
+ ifilter: function (pred, seq) {
+ var m = MochiKit.Base;
+ seq = MochiKit.Iter.iter(seq);
+ if (pred === null) {
+ pred = m.operator.truth;
+ }
+ return {
+ repr: function () { return "ifilter(...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ while (true) {
+ var rval = seq.next();
+ if (pred(rval)) {
+ return rval;
+ }
+ }
+ // mozilla warnings aren't too bright
+ return undefined;
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.ifilterfalse */
+ ifilterfalse: function (pred, seq) {
+ var m = MochiKit.Base;
+ seq = MochiKit.Iter.iter(seq);
+ if (pred === null) {
+ pred = m.operator.truth;
+ }
+ return {
+ repr: function () { return "ifilterfalse(...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ while (true) {
+ var rval = seq.next();
+ if (!pred(rval)) {
+ return rval;
+ }
+ }
+ // mozilla warnings aren't too bright
+ return undefined;
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.islice */
+ islice: function (seq/*, [start,] stop[, step] */) {
+ var self = MochiKit.Iter;
+ var m = MochiKit.Base;
+ seq = self.iter(seq);
+ var start = 0;
+ var stop = 0;
+ var step = 1;
+ var i = -1;
+ if (arguments.length == 2) {
+ stop = arguments[1];
+ } else if (arguments.length == 3) {
+ start = arguments[1];
+ stop = arguments[2];
+ } else {
+ start = arguments[1];
+ stop = arguments[2];
+ step = arguments[3];
+ }
+ return {
+ repr: function () {
+ return "islice(" + ["...", start, stop, step].join(", ") + ")";
+ },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ if (start >= stop) {
+ throw self.StopIteration;
+ }
+
+ var rval;
+ while (i < start) {
+ rval = seq.next();
+ i++;
+ }
+ start += step;
+ return rval;
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.imap */
+ imap: function (fun, p, q/*, ...*/) {
+ var m = MochiKit.Base;
+ var self = MochiKit.Iter;
+ var iterables = m.map(self.iter, m.extend(null, arguments, 1));
+ var map = m.map;
+ var next = self.next;
+ return {
+ repr: function () { return "imap(...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ return fun.apply(this, map(next, iterables));
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.applymap */
+ applymap: function (fun, seq, self) {
+ seq = MochiKit.Iter.iter(seq);
+ var m = MochiKit.Base;
+ return {
+ repr: function () { return "applymap(...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ return fun.apply(self, seq.next());
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.chain */
+ chain: function (p, q/*, ...*/) {
+ // dumb fast path
+ var self = MochiKit.Iter;
+ var m = MochiKit.Base;
+ if (arguments.length == 1) {
+ return self.iter(arguments[0]);
+ }
+ var argiter = m.map(self.iter, arguments);
+ return {
+ repr: function () { return "chain(...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ while (argiter.length > 1) {
+ try {
+ return argiter[0].next();
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ argiter.shift();
+ }
+ }
+ if (argiter.length == 1) {
+ // optimize last element
+ var arg = argiter.shift();
+ this.next = m.bind("next", arg);
+ return this.next();
+ }
+ throw self.StopIteration;
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.takewhile */
+ takewhile: function (pred, seq) {
+ var self = MochiKit.Iter;
+ seq = self.iter(seq);
+ return {
+ repr: function () { return "takewhile(...)"; },
+ toString: MochiKit.Base.forwardCall("repr"),
+ next: function () {
+ var rval = seq.next();
+ if (!pred(rval)) {
+ this.next = function () {
+ throw self.StopIteration;
+ };
+ this.next();
+ }
+ return rval;
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.dropwhile */
+ dropwhile: function (pred, seq) {
+ seq = MochiKit.Iter.iter(seq);
+ var m = MochiKit.Base;
+ var bind = m.bind;
+ return {
+ "repr": function () { return "dropwhile(...)"; },
+ "toString": m.forwardCall("repr"),
+ "next": function () {
+ while (true) {
+ var rval = seq.next();
+ if (!pred(rval)) {
+ break;
+ }
+ }
+ this.next = bind("next", seq);
+ return rval;
+ }
+ };
+ },
+
+ _tee: function (ident, sync, iterable) {
+ sync.pos[ident] = -1;
+ var m = MochiKit.Base;
+ var listMin = m.listMin;
+ return {
+ repr: function () { return "tee(" + ident + ", ...)"; },
+ toString: m.forwardCall("repr"),
+ next: function () {
+ var rval;
+ var i = sync.pos[ident];
+
+ if (i == sync.max) {
+ rval = iterable.next();
+ sync.deque.push(rval);
+ sync.max += 1;
+ sync.pos[ident] += 1;
+ } else {
+ rval = sync.deque[i - sync.min];
+ sync.pos[ident] += 1;
+ if (i == sync.min && listMin(sync.pos) != sync.min) {
+ sync.min += 1;
+ sync.deque.shift();
+ }
+ }
+ return rval;
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.tee */
+ tee: function (iterable, n/* = 2 */) {
+ var rval = [];
+ var sync = {
+ "pos": [],
+ "deque": [],
+ "max": -1,
+ "min": -1
+ };
+ if (arguments.length == 1 || typeof(n) == "undefined" || n === null) {
+ n = 2;
+ }
+ var self = MochiKit.Iter;
+ iterable = self.iter(iterable);
+ var _tee = self._tee;
+ for (var i = 0; i < n; i++) {
+ rval.push(_tee(i, sync, iterable));
+ }
+ return rval;
+ },
+
+ /** @id MochiKit.Iter.list */
+ list: function (iterable) {
+ // Fast-path for Array and Array-like
+ var rval;
+ if (iterable instanceof Array) {
+ return iterable.slice();
+ }
+ // this is necessary to avoid a Safari crash
+ if (typeof(iterable) == "function" &&
+ !(iterable instanceof Function) &&
+ typeof(iterable.length) == 'number') {
+ rval = [];
+ for (var i = 0; i < iterable.length; i++) {
+ rval.push(iterable[i]);
+ }
+ return rval;
+ }
+
+ var self = MochiKit.Iter;
+ iterable = self.iter(iterable);
+ rval = [];
+ var a_val;
+ try {
+ while (true) {
+ a_val = iterable.next();
+ rval.push(a_val);
+ }
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ return rval;
+ }
+ // mozilla warnings aren't too bright
+ return undefined;
+ },
+
+
+ /** @id MochiKit.Iter.reduce */
+ reduce: function (fn, iterable, /* optional */initial) {
+ var i = 0;
+ var x = initial;
+ var self = MochiKit.Iter;
+ iterable = self.iter(iterable);
+ if (arguments.length < 3) {
+ try {
+ x = iterable.next();
+ } catch (e) {
+ if (e == self.StopIteration) {
+ e = new TypeError("reduce() of empty sequence with no initial value");
+ }
+ throw e;
+ }
+ i++;
+ }
+ try {
+ while (true) {
+ x = fn(x, iterable.next());
+ }
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ }
+ return x;
+ },
+
+ /** @id MochiKit.Iter.range */
+ range: function (/* [start,] stop[, step] */) {
+ var start = 0;
+ var stop = 0;
+ var step = 1;
+ if (arguments.length == 1) {
+ stop = arguments[0];
+ } else if (arguments.length == 2) {
+ start = arguments[0];
+ stop = arguments[1];
+ } else if (arguments.length == 3) {
+ start = arguments[0];
+ stop = arguments[1];
+ step = arguments[2];
+ } else {
+ throw new TypeError("range() takes 1, 2, or 3 arguments!");
+ }
+ if (step === 0) {
+ throw new TypeError("range() step must not be 0");
+ }
+ return {
+ next: function () {
+ if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
+ throw MochiKit.Iter.StopIteration;
+ }
+ var rval = start;
+ start += step;
+ return rval;
+ },
+ repr: function () {
+ return "range(" + [start, stop, step].join(", ") + ")";
+ },
+ toString: MochiKit.Base.forwardCall("repr")
+ };
+ },
+
+ /** @id MochiKit.Iter.sum */
+ sum: function (iterable, start/* = 0 */) {
+ if (typeof(start) == "undefined" || start === null) {
+ start = 0;
+ }
+ var x = start;
+ var self = MochiKit.Iter;
+ iterable = self.iter(iterable);
+ try {
+ while (true) {
+ x += iterable.next();
+ }
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ }
+ return x;
+ },
+
+ /** @id MochiKit.Iter.exhaust */
+ exhaust: function (iterable) {
+ var self = MochiKit.Iter;
+ iterable = self.iter(iterable);
+ try {
+ while (true) {
+ iterable.next();
+ }
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ }
+ },
+
+ /** @id MochiKit.Iter.forEach */
+ forEach: function (iterable, func, /* optional */obj) {
+ var m = MochiKit.Base;
+ var self = MochiKit.Iter;
+ if (arguments.length > 2) {
+ func = m.bind(func, obj);
+ }
+ // fast path for array
+ if (m.isArrayLike(iterable) && !self.isIterable(iterable)) {
+ try {
+ for (var i = 0; i < iterable.length; i++) {
+ func(iterable[i]);
+ }
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ }
+ } else {
+ self.exhaust(self.imap(func, iterable));
+ }
+ },
+
+ /** @id MochiKit.Iter.every */
+ every: function (iterable, func) {
+ var self = MochiKit.Iter;
+ try {
+ self.ifilterfalse(func, iterable).next();
+ return false;
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ return true;
+ }
+ },
+
+ /** @id MochiKit.Iter.sorted */
+ sorted: function (iterable, /* optional */cmp) {
+ var rval = MochiKit.Iter.list(iterable);
+ if (arguments.length == 1) {
+ cmp = MochiKit.Base.compare;
+ }
+ rval.sort(cmp);
+ return rval;
+ },
+
+ /** @id MochiKit.Iter.reversed */
+ reversed: function (iterable) {
+ var rval = MochiKit.Iter.list(iterable);
+ rval.reverse();
+ return rval;
+ },
+
+ /** @id MochiKit.Iter.some */
+ some: function (iterable, func) {
+ var self = MochiKit.Iter;
+ try {
+ self.ifilter(func, iterable).next();
+ return true;
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ return false;
+ }
+ },
+
+ /** @id MochiKit.Iter.iextend */
+ iextend: function (lst, iterable) {
+ var m = MochiKit.Base;
+ var self = MochiKit.Iter;
+ if (m.isArrayLike(iterable) && !self.isIterable(iterable)) {
+ // fast-path for array-like
+ for (var i = 0; i < iterable.length; i++) {
+ lst.push(iterable[i]);
+ }
+ } else {
+ iterable = self.iter(iterable);
+ try {
+ while (true) {
+ lst.push(iterable.next());
+ }
+ } catch (e) {
+ if (e != self.StopIteration) {
+ throw e;
+ }
+ }
+ }
+ return lst;
+ },
+
+ /** @id MochiKit.Iter.groupby */
+ groupby: function(iterable, /* optional */ keyfunc) {
+ var m = MochiKit.Base;
+ var self = MochiKit.Iter;
+ if (arguments.length < 2) {
+ keyfunc = m.operator.identity;
+ }
+ iterable = self.iter(iterable);
+
+ // shared
+ var pk = undefined;
+ var k = undefined;
+ var v;
+
+ function fetch() {
+ v = iterable.next();
+ k = keyfunc(v);
+ };
+
+ function eat() {
+ var ret = v;
+ v = undefined;
+ return ret;
+ };
+
+ var first = true;
+ var compare = m.compare;
+ return {
+ repr: function () { return "groupby(...)"; },
+ next: function() {
+ // iterator-next
+
+ // iterate until meet next group
+ while (compare(k, pk) === 0) {
+ fetch();
+ if (first) {
+ first = false;
+ break;
+ }
+ }
+ pk = k;
+ return [k, {
+ next: function() {
+ // subiterator-next
+ if (v == undefined) { // Is there something to eat?
+ fetch();
+ }
+ if (compare(k, pk) !== 0) {
+ throw self.StopIteration;
+ }
+ return eat();
+ }
+ }];
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.groupby_as_array */
+ groupby_as_array: function (iterable, /* optional */ keyfunc) {
+ var m = MochiKit.Base;
+ var self = MochiKit.Iter;
+ if (arguments.length < 2) {
+ keyfunc = m.operator.identity;
+ }
+
+ iterable = self.iter(iterable);
+ var result = [];
+ var first = true;
+ var prev_key;
+ var compare = m.compare;
+ while (true) {
+ try {
+ var value = iterable.next();
+ var key = keyfunc(value);
+ } catch (e) {
+ if (e == self.StopIteration) {
+ break;
+ }
+ throw e;
+ }
+ if (first || compare(key, prev_key) !== 0) {
+ var values = [];
+ result.push([key, values]);
+ }
+ values.push(value);
+ first = false;
+ prev_key = key;
+ }
+ return result;
+ },
+
+ /** @id MochiKit.Iter.arrayLikeIter */
+ arrayLikeIter: function (iterable) {
+ var i = 0;
+ return {
+ repr: function () { return "arrayLikeIter(...)"; },
+ toString: MochiKit.Base.forwardCall("repr"),
+ next: function () {
+ if (i >= iterable.length) {
+ throw MochiKit.Iter.StopIteration;
+ }
+ return iterable[i++];
+ }
+ };
+ },
+
+ /** @id MochiKit.Iter.hasIterateNext */
+ hasIterateNext: function (iterable) {
+ return (iterable && typeof(iterable.iterateNext) == "function");
+ },
+
+ /** @id MochiKit.Iter.iterateNextIter */
+ iterateNextIter: function (iterable) {
+ return {
+ repr: function () { return "iterateNextIter(...)"; },
+ toString: MochiKit.Base.forwardCall("repr"),
+ next: function () {
+ var rval = iterable.iterateNext();
+ if (rval === null || rval === undefined) {
+ throw MochiKit.Iter.StopIteration;
+ }
+ return rval;
+ }
+ };
+ }
+});
+
+
+MochiKit.Iter.__new__ = function () {
+ var m = MochiKit.Base;
+ // Re-use StopIteration if exists (e.g. SpiderMonkey)
+ if (typeof(StopIteration) != "undefined") {
+ this.StopIteration = StopIteration;
+ } else {
+ /** @id MochiKit.Iter.StopIteration */
+ this.StopIteration = new m.NamedError("StopIteration");
+ }
+ this.iteratorRegistry = new m.AdapterRegistry();
+ // Register the iterator factory for arrays
+ this.registerIteratorFactory(
+ "arrayLike",
+ m.isArrayLike,
+ this.arrayLikeIter
+ );
+
+ this.registerIteratorFactory(
+ "iterateNext",
+ this.hasIterateNext,
+ this.iterateNextIter
+ );
+
+ m.nameFunctions(this);
+
+};
+
+MochiKit.Iter.__new__();
+
+//
+// XXX: Internet Explorer blows
+//
+if (MochiKit.__export__) {
+ reduce = MochiKit.Iter.reduce;
+}
+
+MochiKit.Base._exportSymbols(this, MochiKit.Iter);
diff --git a/frontend/delta/js/MochiKit/Logging.js b/frontend/delta/js/MochiKit/Logging.js
new file mode 100644
index 0000000..34070bc
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Logging.js
@@ -0,0 +1,285 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Logging 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Logging', '1.5', ['Base']);
+
+ /** @id MochiKit.Logging.LogMessage */
+MochiKit.Logging.LogMessage = function (num, level, info) {
+ this.num = num;
+ this.level = level;
+ this.info = info;
+ this.timestamp = new Date();
+};
+
+MochiKit.Logging.LogMessage.prototype = {
+ /** @id MochiKit.Logging.LogMessage.prototype.repr */
+ repr: function () {
+ var m = MochiKit.Base;
+ return 'LogMessage(' +
+ m.map(
+ m.repr,
+ [this.num, this.level, this.info]
+ ).join(', ') + ')';
+ },
+ /** @id MochiKit.Logging.LogMessage.prototype.toString */
+ toString: MochiKit.Base.forwardCall("repr")
+};
+
+MochiKit.Base.update(MochiKit.Logging, {
+ /** @id MochiKit.Logging.logLevelAtLeast */
+ logLevelAtLeast: function (minLevel) {
+ var self = MochiKit.Logging;
+ if (typeof(minLevel) == 'string') {
+ minLevel = self.LogLevel[minLevel];
+ }
+ return function (msg) {
+ var msgLevel = msg.level;
+ if (typeof(msgLevel) == 'string') {
+ msgLevel = self.LogLevel[msgLevel];
+ }
+ return msgLevel >= minLevel;
+ };
+ },
+
+ /** @id MochiKit.Logging.isLogMessage */
+ isLogMessage: function (/* ... */) {
+ var LogMessage = MochiKit.Logging.LogMessage;
+ for (var i = 0; i < arguments.length; i++) {
+ if (!(arguments[i] instanceof LogMessage)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /** @id MochiKit.Logging.compareLogMessage */
+ compareLogMessage: function (a, b) {
+ return MochiKit.Base.compare([a.level, a.info], [b.level, b.info]);
+ },
+
+ /** @id MochiKit.Logging.alertListener */
+ alertListener: function (msg) {
+ alert(
+ "num: " + msg.num +
+ "\nlevel: " + msg.level +
+ "\ninfo: " + msg.info.join(" ")
+ );
+ }
+
+});
+
+/** @id MochiKit.Logging.Logger */
+MochiKit.Logging.Logger = function (/* optional */maxSize) {
+ this.counter = 0;
+ if (typeof(maxSize) == 'undefined' || maxSize === null) {
+ maxSize = -1;
+ }
+ this.maxSize = maxSize;
+ this._messages = [];
+ this.listeners = {};
+ this.useNativeConsole = false;
+};
+
+MochiKit.Logging.Logger.prototype = {
+ /** @id MochiKit.Logging.Logger.prototype.clear */
+ clear: function () {
+ this._messages.splice(0, this._messages.length);
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.logToConsole */
+ logToConsole: function (msg) {
+ if (typeof(window) != "undefined" && window.console
+ && window.console.log) {
+ // Safari and FireBug 0.4
+ // Percent replacement is a workaround for cute Safari crashing bug
+ window.console.log(msg.replace(/%/g, '\uFF05'));
+ } else if (typeof(opera) != "undefined" && opera.postError) {
+ // Opera
+ opera.postError(msg);
+ } else if (typeof(Debug) != "undefined" && Debug.writeln) {
+ // IE Web Development Helper (?)
+ // http://www.nikhilk.net/Entry.aspx?id=93
+ Debug.writeln(msg);
+ } else if (typeof(debug) != "undefined" && debug.trace) {
+ // Atlas framework (?)
+ // http://www.nikhilk.net/Entry.aspx?id=93
+ debug.trace(msg);
+ }
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.dispatchListeners */
+ dispatchListeners: function (msg) {
+ for (var k in this.listeners) {
+ var pair = this.listeners[k];
+ if (pair.ident != k || (pair[0] && !pair[0](msg))) {
+ continue;
+ }
+ pair[1](msg);
+ }
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.addListener */
+ addListener: function (ident, filter, listener) {
+ if (typeof(filter) == 'string') {
+ filter = MochiKit.Logging.logLevelAtLeast(filter);
+ }
+ var entry = [filter, listener];
+ entry.ident = ident;
+ this.listeners[ident] = entry;
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.removeListener */
+ removeListener: function (ident) {
+ delete this.listeners[ident];
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.baseLog */
+ baseLog: function (level, message/*, ...*/) {
+ if (typeof(level) == "number") {
+ if (level >= MochiKit.Logging.LogLevel.FATAL) {
+ level = 'FATAL';
+ } else if (level >= MochiKit.Logging.LogLevel.ERROR) {
+ level = 'ERROR';
+ } else if (level >= MochiKit.Logging.LogLevel.WARNING) {
+ level = 'WARNING';
+ } else if (level >= MochiKit.Logging.LogLevel.INFO) {
+ level = 'INFO';
+ } else {
+ level = 'DEBUG';
+ }
+ }
+ var msg = new MochiKit.Logging.LogMessage(
+ this.counter,
+ level,
+ MochiKit.Base.extend(null, arguments, 1)
+ );
+ this._messages.push(msg);
+ this.dispatchListeners(msg);
+ if (this.useNativeConsole) {
+ this.logToConsole(msg.level + ": " + msg.info.join(" "));
+ }
+ this.counter += 1;
+ while (this.maxSize >= 0 && this._messages.length > this.maxSize) {
+ this._messages.shift();
+ }
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.getMessages */
+ getMessages: function (howMany) {
+ var firstMsg = 0;
+ if (!(typeof(howMany) == 'undefined' || howMany === null)) {
+ firstMsg = Math.max(0, this._messages.length - howMany);
+ }
+ return this._messages.slice(firstMsg);
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.getMessageText */
+ getMessageText: function (howMany) {
+ if (typeof(howMany) == 'undefined' || howMany === null) {
+ howMany = 30;
+ }
+ var messages = this.getMessages(howMany);
+ if (messages.length) {
+ var lst = MochiKit.Base.map(function (m) {
+ return '\n [' + m.num + '] ' + m.level + ': ' + m.info.join(' ');
+ }, messages);
+ lst.unshift('LAST ' + messages.length + ' MESSAGES:');
+ return lst.join('');
+ }
+ return '';
+ },
+
+ /** @id MochiKit.Logging.Logger.prototype.debuggingBookmarklet */
+ debuggingBookmarklet: function (inline) {
+ if (typeof(MochiKit.LoggingPane) == "undefined") {
+ alert(this.getMessageText());
+ } else {
+ MochiKit.LoggingPane.createLoggingPane(inline || false);
+ }
+ }
+};
+
+MochiKit.Logging.__new__ = function () {
+ this.LogLevel = {
+ ERROR: 40,
+ FATAL: 50,
+ WARNING: 30,
+ INFO: 20,
+ DEBUG: 10
+ };
+
+ var m = MochiKit.Base;
+ m.registerComparator("LogMessage",
+ this.isLogMessage,
+ this.compareLogMessage
+ );
+
+ var partial = m.partial;
+
+ var Logger = this.Logger;
+ var baseLog = Logger.prototype.baseLog;
+ m.update(this.Logger.prototype, {
+ debug: partial(baseLog, 'DEBUG'),
+ log: partial(baseLog, 'INFO'),
+ error: partial(baseLog, 'ERROR'),
+ fatal: partial(baseLog, 'FATAL'),
+ warning: partial(baseLog, 'WARNING')
+ });
+
+ // indirectly find logger so it can be replaced
+ var self = this;
+ var connectLog = function (name) {
+ return function () {
+ self.logger[name].apply(self.logger, arguments);
+ };
+ };
+
+ /** @id MochiKit.Logging.log */
+ this.log = connectLog('log');
+ /** @id MochiKit.Logging.logError */
+ this.logError = connectLog('error');
+ /** @id MochiKit.Logging.logDebug */
+ this.logDebug = connectLog('debug');
+ /** @id MochiKit.Logging.logFatal */
+ this.logFatal = connectLog('fatal');
+ /** @id MochiKit.Logging.logWarning */
+ this.logWarning = connectLog('warning');
+ this.logger = new Logger();
+ this.logger.useNativeConsole = true;
+
+ m.nameFunctions(this);
+};
+
+MochiKit.Logging.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.Logging);
diff --git a/frontend/delta/js/MochiKit/LoggingPane.js b/frontend/delta/js/MochiKit/LoggingPane.js
new file mode 100644
index 0000000..e35aee8
--- /dev/null
+++ b/frontend/delta/js/MochiKit/LoggingPane.js
@@ -0,0 +1,353 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.LoggingPane 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'LoggingPane', '1.5', ['Base', 'Logging']);
+
+/** @id MochiKit.LoggingPane.createLoggingPane */
+MochiKit.LoggingPane.createLoggingPane = function (inline/* = false */) {
+ var m = MochiKit.LoggingPane;
+ inline = !(!inline);
+ if (m._loggingPane && m._loggingPane.inline != inline) {
+ m._loggingPane.closePane();
+ m._loggingPane = null;
+ }
+ if (!m._loggingPane || m._loggingPane.closed) {
+ m._loggingPane = new m.LoggingPane(inline, MochiKit.Logging.logger);
+ }
+ return m._loggingPane;
+};
+
+/**
+ * @id MochiKit.LoggingPane.LoggingPane
+ * @constructor
+ */
+MochiKit.LoggingPane.LoggingPane = function (inline/* = false */, logger/* = MochiKit.Logging.logger */) {
+
+ /* Use a div if inline, pop up a window if not */
+ /* Create the elements */
+ if (typeof(logger) == "undefined" || logger === null) {
+ logger = MochiKit.Logging.logger;
+ }
+ this.logger = logger;
+ var update = MochiKit.Base.update;
+ var updatetree = MochiKit.Base.updatetree;
+ var bind = MochiKit.Base.bind;
+ var clone = MochiKit.Base.clone;
+ var win = window;
+ var uid = "_MochiKit_LoggingPane";
+ if (typeof(MochiKit.DOM) != "undefined") {
+ win = MochiKit.DOM.currentWindow();
+ }
+ if (!inline) {
+ // name the popup with the base URL for uniqueness
+ var url = win.location.href.split("?")[0].replace(/[#:\/.><&%-]/g, "_");
+ var name = uid + "_" + url;
+ var nwin = win.open("", name, "dependent,resizable,height=200");
+ if (!nwin) {
+ alert("Not able to open debugging window due to pop-up blocking.");
+ return undefined;
+ }
+ nwin.document.write(
+ ''
+ + '[MochiKit.LoggingPane]'
+ + ''
+ );
+ nwin.document.close();
+ nwin.document.title += ' ' + win.document.title;
+ win = nwin;
+ }
+ var doc = win.document;
+ this.doc = doc;
+
+ // Connect to the debug pane if it already exists (i.e. in a window orphaned by the page being refreshed)
+ var debugPane = doc.getElementById(uid);
+ var existing_pane = !!debugPane;
+ if (debugPane && typeof(debugPane.loggingPane) != "undefined") {
+ debugPane.loggingPane.logger = this.logger;
+ debugPane.loggingPane.buildAndApplyFilter();
+ return debugPane.loggingPane;
+ }
+
+ if (existing_pane) {
+ // clear any existing contents
+ var child;
+ while ((child = debugPane.firstChild)) {
+ debugPane.removeChild(child);
+ }
+ } else {
+ debugPane = doc.createElement("div");
+ debugPane.id = uid;
+ }
+ debugPane.loggingPane = this;
+ var levelFilterField = doc.createElement("input");
+ var infoFilterField = doc.createElement("input");
+ var filterButton = doc.createElement("button");
+ var loadButton = doc.createElement("button");
+ var clearButton = doc.createElement("button");
+ var closeButton = doc.createElement("button");
+ var logPaneArea = doc.createElement("div");
+ var logPane = doc.createElement("div");
+
+ /* Set up the functions */
+ var listenerId = uid + "_Listener";
+ this.colorTable = clone(this.colorTable);
+ var messages = [];
+ var messageFilter = null;
+
+ /** @id MochiKit.LoggingPane.messageLevel */
+ var messageLevel = function (msg) {
+ var level = msg.level;
+ if (typeof(level) == "number") {
+ level = MochiKit.Logging.LogLevel[level];
+ }
+ return level;
+ };
+
+ /** @id MochiKit.LoggingPane.messageText */
+ var messageText = function (msg) {
+ return msg.info.join(" ");
+ };
+
+ /** @id MochiKit.LoggingPane.addMessageText */
+ var addMessageText = bind(function (msg) {
+ var level = messageLevel(msg);
+ var text = messageText(msg);
+ var c = this.colorTable[level];
+ var p = doc.createElement("span");
+ p.className = "MochiKit-LogMessage MochiKit-LogLevel-" + level;
+ p.style.cssText = "margin: 0px; white-space: -moz-pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; wrap-option: emergency; color: " + c;
+ p.appendChild(doc.createTextNode(level + ": " + text));
+ logPane.appendChild(p);
+ logPane.appendChild(doc.createElement("br"));
+ if (logPaneArea.offsetHeight > logPaneArea.scrollHeight) {
+ logPaneArea.scrollTop = 0;
+ } else {
+ logPaneArea.scrollTop = logPaneArea.scrollHeight;
+ }
+ }, this);
+
+ /** @id MochiKit.LoggingPane.addMessage */
+ var addMessage = function (msg) {
+ messages[messages.length] = msg;
+ addMessageText(msg);
+ };
+
+ /** @id MochiKit.LoggingPane.buildMessageFilter */
+ var buildMessageFilter = function () {
+ var levelre, infore;
+ try {
+ /* Catch any exceptions that might arise due to invalid regexes */
+ levelre = new RegExp(levelFilterField.value);
+ infore = new RegExp(infoFilterField.value);
+ } catch(e) {
+ /* If there was an error with the regexes, do no filtering */
+ MochiKit.Logging.logDebug("Error in filter regex: " + e.message);
+ return null;
+ }
+
+ return function (msg) {
+ return (
+ levelre.test(messageLevel(msg)) &&
+ infore.test(messageText(msg))
+ );
+ };
+ };
+
+ /** @id MochiKit.LoggingPane.clearMessagePane */
+ var clearMessagePane = function () {
+ while (logPane.firstChild) {
+ logPane.removeChild(logPane.firstChild);
+ }
+ };
+
+ /** @id MochiKit.LoggingPane.clearMessages */
+ var clearMessages = function () {
+ messages = [];
+ clearMessagePane();
+ };
+
+ /** @id MochiKit.LoggingPane.closePane */
+ var closePane = bind(function () {
+ if (this.closed) {
+ return;
+ }
+ this.closed = true;
+ if (MochiKit.LoggingPane._loggingPane == this) {
+ MochiKit.LoggingPane._loggingPane = null;
+ }
+ this.logger.removeListener(listenerId);
+ try {
+ try {
+ debugPane.loggingPane = null;
+ } catch(e) { MochiKit.Logging.logFatal("Bookmarklet was closed incorrectly."); }
+ if (inline) {
+ debugPane.parentNode.removeChild(debugPane);
+ } else {
+ this.win.close();
+ }
+ } catch(e) {}
+ }, this);
+
+ /** @id MochiKit.LoggingPane.filterMessages */
+ var filterMessages = function () {
+ clearMessagePane();
+
+ for (var i = 0; i < messages.length; i++) {
+ var msg = messages[i];
+ if (messageFilter === null || messageFilter(msg)) {
+ addMessageText(msg);
+ }
+ }
+ };
+
+ this.buildAndApplyFilter = function () {
+ messageFilter = buildMessageFilter();
+
+ filterMessages();
+
+ this.logger.removeListener(listenerId);
+ this.logger.addListener(listenerId, messageFilter, addMessage);
+ };
+
+
+ /** @id MochiKit.LoggingPane.loadMessages */
+ var loadMessages = bind(function () {
+ messages = this.logger.getMessages();
+ filterMessages();
+ }, this);
+
+ /** @id MochiKit.LoggingPane.filterOnEnter */
+ var filterOnEnter = bind(function (event) {
+ event = event || window.event;
+ var key = event.which || event.keyCode;
+ if (key == 13) {
+ this.buildAndApplyFilter();
+ }
+ }, this);
+
+ /* Create the debug pane */
+ var style = "display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: " + this.logFont;
+ if (inline) {
+ style += "; height: 10em; border-top: 2px solid black";
+ } else {
+ style += "; height: 100%;";
+ }
+ debugPane.style.cssText = style;
+
+ if (!existing_pane) {
+ doc.body.appendChild(debugPane);
+ }
+
+ /* Create the filter fields */
+ style = {"cssText": "width: 33%; display: inline; font: " + this.logFont};
+
+ updatetree(levelFilterField, {
+ "value": "FATAL|ERROR|WARNING|INFO|DEBUG",
+ "onkeypress": filterOnEnter,
+ "style": style
+ });
+ debugPane.appendChild(levelFilterField);
+
+ updatetree(infoFilterField, {
+ "value": ".*",
+ "onkeypress": filterOnEnter,
+ "style": style
+ });
+ debugPane.appendChild(infoFilterField);
+
+ /* Create the buttons */
+ style = "width: 8%; display:inline; font: " + this.logFont;
+
+ filterButton.appendChild(doc.createTextNode("Filter"));
+ filterButton.onclick = bind("buildAndApplyFilter", this);
+ filterButton.style.cssText = style;
+ debugPane.appendChild(filterButton);
+
+ loadButton.appendChild(doc.createTextNode("Load"));
+ loadButton.onclick = loadMessages;
+ loadButton.style.cssText = style;
+ debugPane.appendChild(loadButton);
+
+ clearButton.appendChild(doc.createTextNode("Clear"));
+ clearButton.onclick = clearMessages;
+ clearButton.style.cssText = style;
+ debugPane.appendChild(clearButton);
+
+ closeButton.appendChild(doc.createTextNode("Close"));
+ closeButton.onclick = closePane;
+ closeButton.style.cssText = style;
+ debugPane.appendChild(closeButton);
+
+ /* Create the logging pane */
+ logPaneArea.style.cssText = "overflow: auto; width: 100%";
+ logPane.style.cssText = "width: 100%; height: " + (inline ? "8em" : "100%");
+
+ logPaneArea.appendChild(logPane);
+ debugPane.appendChild(logPaneArea);
+
+ this.buildAndApplyFilter();
+ loadMessages();
+
+ if (inline) {
+ this.win = undefined;
+ } else {
+ this.win = win;
+ }
+ this.inline = inline;
+ this.closePane = closePane;
+ this.closed = false;
+
+
+ return this;
+};
+
+MochiKit.LoggingPane.LoggingPane.prototype = {
+ "logFont": "8pt Verdana,sans-serif",
+ "colorTable": {
+ "ERROR": "red",
+ "FATAL": "darkred",
+ "WARNING": "blue",
+ "INFO": "black",
+ "DEBUG": "green"
+ }
+};
+
+MochiKit.LoggingPane.__new__ = function () {
+ MochiKit.Base.nameFunctions(this);
+ MochiKit.LoggingPane._loggingPane = null;
+};
+
+MochiKit.LoggingPane.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.LoggingPane);
diff --git a/frontend/delta/js/MochiKit/MochiKit.js b/frontend/delta/js/MochiKit/MochiKit.js
new file mode 100644
index 0000000..5fac077
--- /dev/null
+++ b/frontend/delta/js/MochiKit/MochiKit.js
@@ -0,0 +1,156 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.MochiKit 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+var MochiKit = MochiKit || {};
+
+/** @id MochiKit.MochiKit */
+MochiKit.MochiKit = MochiKit.MochiKit || {};
+
+MochiKit.MochiKit.NAME = "MochiKit.MochiKit";
+MochiKit.MochiKit.VERSION = "1.5";
+MochiKit.MochiKit.__export__ = false;
+MochiKit.MochiKit.__repr__ = function () {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+};
+
+/** @id MochiKit.MochiKit.toString */
+MochiKit.MochiKit.toString = function () {
+ return this.__repr__();
+};
+
+/** @id MochiKit.MochiKit.SUBMODULES */
+MochiKit.MochiKit.SUBMODULES = [
+ "Base",
+ "Iter",
+ "Logging",
+ "DateTime",
+ "Format",
+ "Text",
+ "Async",
+ "DOM",
+ "Selector",
+ "Style",
+ "LoggingPane",
+ "Color",
+ "Signal",
+ "Position",
+ "Visual",
+ "DragAndDrop",
+ "Sortable"
+];
+
+(function () {
+ if (typeof(document) == "undefined") {
+ return;
+ }
+ var scripts = document.getElementsByTagName("script");
+ var kXHTMLNSURI = "http://www.w3.org/1999/xhtml";
+ var kSVGNSURI = "http://www.w3.org/2000/svg";
+ var kXLINKNSURI = "http://www.w3.org/1999/xlink";
+ var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+ var base = null;
+ var baseElem = null;
+ var allScripts = {};
+ var i;
+ var src;
+ for (i = 0; i < scripts.length; i++) {
+ src = null;
+ switch (scripts[i].namespaceURI) {
+ case kSVGNSURI:
+ src = scripts[i].getAttributeNS(kXLINKNSURI, "href");
+ break;
+ /*
+ case null: // HTML
+ case '': // HTML
+ case kXHTMLNSURI:
+ case kXULNSURI:
+ */
+ default:
+ src = scripts[i].getAttribute("src");
+ break;
+ }
+ if (!src) {
+ continue;
+ }
+ allScripts[src] = true;
+ if (src.match(/MochiKit.js(\?.*)?$/)) {
+ base = src.substring(0, src.lastIndexOf('MochiKit.js'));
+ baseElem = scripts[i];
+ }
+ }
+ if (base === null) {
+ return;
+ }
+ var modules = MochiKit.MochiKit.SUBMODULES;
+ for (var i = 0; i < modules.length; i++) {
+ if (MochiKit[modules[i]]) {
+ continue;
+ }
+ var uri = base + modules[i] + '.js';
+ if (uri in allScripts) {
+ continue;
+ }
+ if (baseElem.namespaceURI == kSVGNSURI ||
+ baseElem.namespaceURI == kXULNSURI) {
+ // SVG, XUL
+ /*
+ SVG does not support document.write, so if Safari wants to
+ support SVG tests it should fix its deferred loading bug
+ (see following below).
+ */
+ var s = document.createElementNS(baseElem.namespaceURI, 'script');
+ s.setAttribute("id", "MochiKit_" + base + modules[i]);
+ if (baseElem.namespaceURI == kSVGNSURI) {
+ s.setAttributeNS(kXLINKNSURI, 'href', uri);
+ } else {
+ s.setAttribute('src', uri);
+ }
+ s.setAttribute("type", "application/x-javascript");
+ baseElem.parentNode.appendChild(s);
+ } else {
+ // HTML, XHTML
+ /*
+ DOM can not be used here because Safari does
+ deferred loading of scripts unless they are
+ in the document or inserted with document.write
+
+ This is not XHTML compliant. If you want XHTML
+ compliance then you must use the packed version of MochiKit
+ or include each script individually (basically unroll
+ these document.write calls into your XHTML source)
+ */
+ document.write('<' + baseElem.nodeName + ' src="' + uri +
+ '" type="text/javascript">');
+ }
+ };
+})();
diff --git a/frontend/delta/js/MochiKit/MockDOM.js b/frontend/delta/js/MochiKit/MockDOM.js
new file mode 100644
index 0000000..6df7922
--- /dev/null
+++ b/frontend/delta/js/MochiKit/MockDOM.js
@@ -0,0 +1,135 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.MockDOM 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+var MochiKit = MochiKit || {};
+
+MochiKit.MockDOM = MochiKit.MockDOM || {};
+
+MochiKit.MockDOM.NAME = "MochiKit.MockDOM";
+MochiKit.MockDOM.VERSION = "1.5";
+MochiKit.MockDOM.__export__ = false;
+
+MochiKit.MockDOM.__repr__ = function () {
+ return "[" + this.NAME + " " + this.VERSION + "]";
+};
+
+/** @id MochiKit.MockDOM.toString */
+MochiKit.MockDOM.toString = function () {
+ return this.__repr__();
+};
+
+/** @id MochiKit.MockDOM.createDocument */
+MochiKit.MockDOM.createDocument = function () {
+ var doc = new MochiKit.MockDOM.MockElement("DOCUMENT");
+ doc.body = doc.createElement("BODY");
+ doc.appendChild(doc.body);
+ return doc;
+};
+
+/** @id MochiKit.MockDOM.MockElement */
+MochiKit.MockDOM.MockElement = function (name, data, ownerDocument) {
+ this.tagName = this.nodeName = name.toUpperCase();
+ this.ownerDocument = ownerDocument || null;
+ if (name == "DOCUMENT") {
+ this.nodeType = 9;
+ this.childNodes = [];
+ } else if (typeof(data) == "string") {
+ this.nodeValue = data;
+ this.nodeType = 3;
+ } else {
+ this.nodeType = 1;
+ this.childNodes = [];
+ }
+ if (name.substring(0, 1) == "<") {
+ var nameattr = name.substring(
+ name.indexOf('"') + 1, name.lastIndexOf('"'));
+ name = name.substring(1, name.indexOf(" "));
+ this.tagName = this.nodeName = name.toUpperCase();
+ this.setAttribute("name", nameattr);
+ }
+};
+
+MochiKit.MockDOM.MockElement.prototype = {
+ /** @id MochiKit.MockDOM.MockElement.prototype.createElement */
+ createElement: function (tagName) {
+ return new MochiKit.MockDOM.MockElement(tagName, null, this.nodeType == 9 ? this : this.ownerDocument);
+ },
+ /** @id MochiKit.MockDOM.MockElement.prototype.createTextNode */
+ createTextNode: function (text) {
+ return new MochiKit.MockDOM.MockElement("text", text, this.nodeType == 9 ? this : this.ownerDocument);
+ },
+ /** @id MochiKit.MockDOM.MockElement.prototype.setAttribute */
+ setAttribute: function (name, value) {
+ this[name] = value;
+ },
+ /** @id MochiKit.MockDOM.MockElement.prototype.getAttribute */
+ getAttribute: function (name) {
+ return this[name];
+ },
+ /** @id MochiKit.MockDOM.MockElement.prototype.appendChild */
+ appendChild: function (child) {
+ this.childNodes.push(child);
+ },
+ /** @id MochiKit.MockDOM.MockElement.prototype.toString */
+ toString: function () {
+ return "MockElement(" + this.tagName + ")";
+ },
+ /** @id MochiKit.MockDOM.MockElement.prototype.getElementsByTagName */
+ getElementsByTagName: function (tagName) {
+ var foundElements = [];
+ MochiKit.Base.nodeWalk(this, function(node){
+ if (tagName == '*' || tagName == node.tagName) {
+ foundElements.push(node);
+ return node.childNodes;
+ }
+ });
+ return foundElements;
+ }
+};
+
+ /** @id MochiKit.MockDOM.EXPORT_OK */
+MochiKit.MockDOM.EXPORT_OK = [
+ "mockElement",
+ "createDocument"
+];
+
+ /** @id MochiKit.MockDOM.EXPORT */
+MochiKit.MockDOM.EXPORT = [
+ "document"
+];
+
+MochiKit.MockDOM.__new__ = function () {
+ this.document = this.createDocument();
+};
+
+MochiKit.MockDOM.__new__();
diff --git a/frontend/delta/js/MochiKit/Position.js b/frontend/delta/js/MochiKit/Position.js
new file mode 100644
index 0000000..e5f4543
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Position.js
@@ -0,0 +1,241 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Position 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005-2006 Bob Ippolito and others. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Position', '1.5', ['Base', 'DOM', 'Style']);
+
+MochiKit.Base.update(MochiKit.Position, {
+ // Don't export from this module
+ __export__: false,
+
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ /** @id MochiKit.Position.prepare */
+ prepare: function () {
+ var deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ var deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ this.windowOffset = new MochiKit.Style.Coordinates(deltaX, deltaY);
+ },
+
+ /** @id MochiKit.Position.cumulativeOffset */
+ cumulativeOffset: function (element) {
+ var valueT = 0;
+ var valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return new MochiKit.Style.Coordinates(valueL, valueT);
+ },
+
+ /** @id MochiKit.Position.realOffset */
+ realOffset: function (element) {
+ var valueT = 0;
+ var valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return new MochiKit.Style.Coordinates(valueL, valueT);
+ },
+
+ /** @id MochiKit.Position.within */
+ within: function (element, x, y) {
+ if (this.includeScrollOffsets) {
+ return this.withinIncludingScrolloffsets(element, x, y);
+ }
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = this.cumulativeOffset(element);
+ if (element.style.position == "fixed") {
+ this.offset.x += this.windowOffset.x;
+ this.offset.y += this.windowOffset.y;
+ }
+
+ return (y >= this.offset.y &&
+ y < this.offset.y + element.offsetHeight &&
+ x >= this.offset.x &&
+ x < this.offset.x + element.offsetWidth);
+ },
+
+ /** @id MochiKit.Position.withinIncludingScrolloffsets */
+ withinIncludingScrolloffsets: function (element, x, y) {
+ var offsetcache = this.realOffset(element);
+
+ this.xcomp = x + offsetcache.x - this.windowOffset.x;
+ this.ycomp = y + offsetcache.y - this.windowOffset.y;
+ this.offset = this.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset.y &&
+ this.ycomp < this.offset.y + element.offsetHeight &&
+ this.xcomp >= this.offset.x &&
+ this.xcomp < this.offset.x + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ /** @id MochiKit.Position.overlap */
+ overlap: function (mode, element) {
+ if (!mode) {
+ return 0;
+ }
+ if (mode == 'vertical') {
+ return ((this.offset.y + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ }
+ if (mode == 'horizontal') {
+ return ((this.offset.x + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ }
+ },
+
+ /** @id MochiKit.Position.absolutize */
+ absolutize: function (element) {
+ element = MochiKit.DOM.getElement(element);
+ if (element.style.position == 'absolute') {
+ return;
+ }
+ MochiKit.Position.prepare();
+
+ var offsets = MochiKit.Position.positionedOffset(element);
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ var oldStyle = {
+ 'position': element.style.position,
+ 'left': offsets.x - parseFloat(element.style.left || 0),
+ 'top': offsets.y - parseFloat(element.style.top || 0),
+ 'width': element.style.width,
+ 'height': element.style.height
+ };
+
+ element.style.position = 'absolute';
+ element.style.top = offsets.y + 'px';
+ element.style.left = offsets.x + 'px';
+ element.style.width = width + 'px';
+ element.style.height = height + 'px';
+
+ return oldStyle;
+ },
+
+ /** @id MochiKit.Position.positionedOffset */
+ positionedOffset: function (element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ var p = MochiKit.Style.getStyle(element, 'position');
+ if (p == 'relative' || p == 'absolute') {
+ break;
+ }
+ }
+ } while (element);
+ return new MochiKit.Style.Coordinates(valueL, valueT);
+ },
+
+ /** @id MochiKit.Position.relativize */
+ relativize: function (element, oldPos) {
+ element = MochiKit.DOM.getElement(element);
+ if (element.style.position == 'relative') {
+ return;
+ }
+ MochiKit.Position.prepare();
+
+ var top = parseFloat(element.style.top || 0) -
+ (oldPos['top'] || 0);
+ var left = parseFloat(element.style.left || 0) -
+ (oldPos['left'] || 0);
+
+ element.style.position = oldPos['position'];
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.width = oldPos['width'];
+ element.style.height = oldPos['height'];
+ },
+
+ /** @id MochiKit.Position.clone */
+ clone: function (source, target) {
+ source = MochiKit.DOM.getElement(source);
+ target = MochiKit.DOM.getElement(target);
+ target.style.position = 'absolute';
+ var offsets = this.cumulativeOffset(source);
+ target.style.top = offsets.y + 'px';
+ target.style.left = offsets.x + 'px';
+ target.style.width = source.offsetWidth + 'px';
+ target.style.height = source.offsetHeight + 'px';
+ },
+
+ /** @id MochiKit.Position.page */
+ page: function (forElement) {
+ var valueT = 0;
+ var valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent == document.body && MochiKit.Style.getStyle(element, 'position') == 'absolute') {
+ break;
+ }
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ } while (element = element.parentNode);
+
+ return new MochiKit.Style.Coordinates(valueL, valueT);
+ }
+});
+
+MochiKit.Position.__new__ = function (win) {
+ MochiKit.Base.nameFunctions(this);
+};
+
+MochiKit.Position.__new__(this);
+
+MochiKit.Base._exportSymbols(this, MochiKit.Position);
diff --git a/frontend/delta/js/MochiKit/Selector.js b/frontend/delta/js/MochiKit/Selector.js
new file mode 100644
index 0000000..2719b13
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Selector.js
@@ -0,0 +1,416 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Selector 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito and others. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Selector', '1.5', ['Base', 'DOM', 'Iter']);
+
+MochiKit.Selector.Selector = function (expression) {
+ this.params = {classNames: [], pseudoClassNames: []};
+ this.expression = expression.toString().replace(/(^\s+|\s+$)/g, '');
+ this.parseExpression();
+ this.compileMatcher();
+};
+
+MochiKit.Selector.Selector.prototype = {
+ /***
+
+ Selector class: convenient object to make CSS selections.
+
+ ***/
+ __class__: MochiKit.Selector.Selector,
+
+ /** @id MochiKit.Selector.Selector.prototype.parseExpression */
+ parseExpression: function () {
+ function abort(message) {
+ throw 'Parse error in selector: ' + message;
+ }
+
+ if (this.expression == '') {
+ abort('empty expression');
+ }
+
+ var repr = MochiKit.Base.repr;
+ var params = this.params;
+ var expr = this.expression;
+ var match, modifier, clause, rest;
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!^$*]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+ params.attributes = params.attributes || [];
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+ expr = match[1];
+ }
+
+ if (expr == '*') {
+ return this.params.wildcard = true;
+ }
+
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+(?:\([^)]*\))?)(.*)/i)) {
+ modifier = match[1];
+ clause = match[2];
+ rest = match[3];
+ switch (modifier) {
+ case '#':
+ params.id = clause;
+ break;
+ case '.':
+ params.classNames.push(clause);
+ break;
+ case ':':
+ params.pseudoClassNames.push(clause);
+ break;
+ case '':
+ case undefined:
+ params.tagName = clause.toUpperCase();
+ break;
+ default:
+ abort(repr(expr));
+ }
+ expr = rest;
+ }
+
+ if (expr.length > 0) {
+ abort(repr(expr));
+ }
+ },
+
+ /** @id MochiKit.Selector.Selector.prototype.buildMatchExpression */
+ buildMatchExpression: function () {
+ var repr = MochiKit.Base.repr;
+ var params = this.params;
+ var conditions = [];
+ var clause, i;
+
+ function childElements(element) {
+ return "MochiKit.Base.filter(function (node) { return node.nodeType == 1; }, " + element + ".childNodes)";
+ }
+
+ if (params.wildcard) {
+ conditions.push('true');
+ }
+ if (clause = params.id) {
+ conditions.push('element.id == ' + repr(clause));
+ }
+ if (clause = params.tagName) {
+ conditions.push('element.tagName.toUpperCase() == ' + repr(clause));
+ }
+ if ((clause = params.classNames).length > 0) {
+ for (i = 0; i < clause.length; i++) {
+ conditions.push('MochiKit.DOM.hasElementClass(element, ' + repr(clause[i]) + ')');
+ }
+ }
+ if ((clause = params.pseudoClassNames).length > 0) {
+ for (i = 0; i < clause.length; i++) {
+ var match = clause[i].match(/^([^(]+)(?:\((.*)\))?$/);
+ var pseudoClass = match[1];
+ var pseudoClassArgument = match[2];
+ switch (pseudoClass) {
+ case 'root':
+ conditions.push('element.nodeType == 9 || element === element.ownerDocument.documentElement'); break;
+ case 'nth-child':
+ case 'nth-last-child':
+ case 'nth-of-type':
+ case 'nth-last-of-type':
+ match = pseudoClassArgument.match(/^((?:(\d+)n\+)?(\d+)|odd|even)$/);
+ if (!match) {
+ throw "Invalid argument to pseudo element nth-child: " + pseudoClassArgument;
+ }
+ var a, b;
+ if (match[0] == 'odd') {
+ a = 2;
+ b = 1;
+ } else if (match[0] == 'even') {
+ a = 2;
+ b = 0;
+ } else {
+ a = match[2] && parseInt(match, 10) || null;
+ b = parseInt(match[3], 10);
+ }
+ conditions.push('this.nthChild(element,' + a + ',' + b
+ + ',' + !!pseudoClass.match('^nth-last') // Reverse
+ + ',' + !!pseudoClass.match('of-type$') // Restrict to same tagName
+ + ')');
+ break;
+ case 'first-child':
+ conditions.push('this.nthChild(element, null, 1)');
+ break;
+ case 'last-child':
+ conditions.push('this.nthChild(element, null, 1, true)');
+ break;
+ case 'first-of-type':
+ conditions.push('this.nthChild(element, null, 1, false, true)');
+ break;
+ case 'last-of-type':
+ conditions.push('this.nthChild(element, null, 1, true, true)');
+ break;
+ case 'only-child':
+ conditions.push(childElements('element.parentNode') + '.length == 1');
+ break;
+ case 'only-of-type':
+ conditions.push('MochiKit.Base.filter(function (node) { return node.tagName == element.tagName; }, ' + childElements('element.parentNode') + ').length == 1');
+ break;
+ case 'empty':
+ conditions.push('element.childNodes.length == 0');
+ break;
+ case 'enabled':
+ conditions.push('(this.isUIElement(element) && element.disabled === false)');
+ break;
+ case 'disabled':
+ conditions.push('(this.isUIElement(element) && element.disabled === true)');
+ break;
+ case 'checked':
+ conditions.push('(this.isUIElement(element) && element.checked === true)');
+ break;
+ case 'not':
+ var subselector = new MochiKit.Selector.Selector(pseudoClassArgument);
+ conditions.push('!( ' + subselector.buildMatchExpression() + ')');
+ break;
+ }
+ }
+ }
+ if (clause = params.attributes) {
+ MochiKit.Base.map(function (attribute) {
+ var value = 'MochiKit.DOM.getNodeAttribute(element, ' + repr(attribute.name) + ')';
+ var splitValueBy = function (delimiter) {
+ return value + '.split(' + repr(delimiter) + ')';
+ };
+ conditions.push(value + ' != null');
+ switch (attribute.operator) {
+ case '=':
+ conditions.push(value + ' == ' + repr(attribute.value));
+ break;
+ case '~=':
+ conditions.push('MochiKit.Base.findValue(' + splitValueBy(' ') + ', ' + repr(attribute.value) + ') > -1');
+ break;
+ case '^=':
+ conditions.push(value + '.substring(0, ' + attribute.value.length + ') == ' + repr(attribute.value));
+ break;
+ case '$=':
+ conditions.push(value + '.substring(' + value + '.length - ' + attribute.value.length + ') == ' + repr(attribute.value));
+ break;
+ case '*=':
+ conditions.push(value + '.match(' + repr(attribute.value) + ')');
+ break;
+ case '|=':
+ conditions.push(splitValueBy('-') + '[0].toUpperCase() == ' + repr(attribute.value.toUpperCase()));
+ break;
+ case '!=':
+ conditions.push(value + ' != ' + repr(attribute.value));
+ break;
+ case '':
+ case undefined:
+ // Condition already added above
+ break;
+ default:
+ throw 'Unknown operator ' + attribute.operator + ' in selector';
+ }
+ }, clause);
+ }
+
+ return conditions.join(' && ');
+ },
+
+ /** @id MochiKit.Selector.Selector.prototype.compileMatcher */
+ compileMatcher: function () {
+ var code = 'return (!element.tagName) ? false : ' +
+ this.buildMatchExpression() + ';';
+ this.match = new Function('element', code);
+ },
+
+ /** @id MochiKit.Selector.Selector.prototype.nthChild */
+ nthChild: function (element, a, b, reverse, sametag){
+ var siblings = MochiKit.Base.filter(function (node) {
+ return node.nodeType == 1;
+ }, element.parentNode.childNodes);
+ if (sametag) {
+ siblings = MochiKit.Base.filter(function (node) {
+ return node.tagName == element.tagName;
+ }, siblings);
+ }
+ if (reverse) {
+ siblings = MochiKit.Iter.reversed(siblings);
+ }
+ if (a) {
+ var actualIndex = MochiKit.Base.findIdentical(siblings, element);
+ return ((actualIndex + 1 - b) / a) % 1 == 0;
+ } else {
+ return b == MochiKit.Base.findIdentical(siblings, element) + 1;
+ }
+ },
+
+ /** @id MochiKit.Selector.Selector.prototype.isUIElement */
+ isUIElement: function (element) {
+ return MochiKit.Base.findValue(['input', 'button', 'select', 'option', 'textarea', 'object'],
+ element.tagName.toLowerCase()) > -1;
+ },
+
+ /** @id MochiKit.Selector.Selector.prototype.findElements */
+ findElements: function (scope, axis) {
+ var element;
+
+ if (axis == undefined) {
+ axis = "";
+ }
+
+ function inScope(element, scope) {
+ if (axis == "") {
+ return MochiKit.DOM.isChildNode(element, scope);
+ } else if (axis == ">") {
+ return element.parentNode === scope;
+ } else if (axis == "+") {
+ return element === nextSiblingElement(scope);
+ } else if (axis == "~") {
+ var sibling = scope;
+ while (sibling = nextSiblingElement(sibling)) {
+ if (element === sibling) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ throw "Invalid axis: " + axis;
+ }
+ }
+
+ if (element = MochiKit.DOM.getElement(this.params.id)) {
+ if (this.match(element)) {
+ if (!scope || inScope(element, scope)) {
+ return [element];
+ }
+ }
+ }
+
+ function nextSiblingElement(node) {
+ node = node.nextSibling;
+ while (node && node.nodeType != 1) {
+ node = node.nextSibling;
+ }
+ return node;
+ }
+
+ if (axis == "") {
+ scope = (scope || MochiKit.DOM.currentDocument()).getElementsByTagName(this.params.tagName || '*');
+ } else if (axis == ">") {
+ if (!scope) {
+ throw "> combinator not allowed without preceeding expression";
+ }
+ scope = MochiKit.Base.filter(function (node) {
+ return node.nodeType == 1;
+ }, scope.childNodes);
+ } else if (axis == "+") {
+ if (!scope) {
+ throw "+ combinator not allowed without preceeding expression";
+ }
+ scope = nextSiblingElement(scope) && [nextSiblingElement(scope)];
+ } else if (axis == "~") {
+ if (!scope) {
+ throw "~ combinator not allowed without preceeding expression";
+ }
+ var newscope = [];
+ while (nextSiblingElement(scope)) {
+ scope = nextSiblingElement(scope);
+ newscope.push(scope);
+ }
+ scope = newscope;
+ }
+
+ if (!scope) {
+ return [];
+ }
+
+ var results = MochiKit.Base.filter(MochiKit.Base.bind(function (scopeElt) {
+ return this.match(scopeElt);
+ }, this), scope);
+
+ return results;
+ },
+
+ /** @id MochiKit.Selector.Selector.prototype.repr */
+ repr: function () {
+ return 'Selector(' + this.expression + ')';
+ },
+
+ toString: MochiKit.Base.forwardCall("repr")
+};
+
+MochiKit.Base.update(MochiKit.Selector, {
+
+ /** @id MochiKit.Selector.findChildElements */
+ findChildElements: function (element, expressions) {
+ element = MochiKit.DOM.getElement(element);
+ var uniq = function(arr) {
+ var res = [];
+ for (var i = 0; i < arr.length; i++) {
+ if (MochiKit.Base.findIdentical(res, arr[i]) < 0) {
+ res.push(arr[i]);
+ }
+ }
+ return res;
+ };
+ return MochiKit.Base.flattenArray(MochiKit.Base.map(function (expression) {
+ try {
+ var res = element.querySelectorAll(expression);
+ return Array.prototype.slice.call(res, 0);
+ } catch (ignore) {
+ // No querySelectorAll or extended expression syntax used
+ }
+ var nextScope = "";
+ var reducer = function (results, expr) {
+ var match = expr.match(/^[>+~]$/);
+ if (match) {
+ nextScope = match[0];
+ return results;
+ } else {
+ var selector = new MochiKit.Selector.Selector(expr);
+ var elements = MochiKit.Iter.reduce(function (elements, result) {
+ return MochiKit.Base.extend(elements, selector.findElements(result || element, nextScope));
+ }, results, []);
+ nextScope = "";
+ return elements;
+ }
+ };
+ var exprs = expression.replace(/(^\s+|\s+$)/g, '').split(/\s+/);
+ return uniq(MochiKit.Iter.reduce(reducer, exprs, [null]));
+ }, expressions));
+ },
+
+ findDocElements: function () {
+ return MochiKit.Selector.findChildElements(MochiKit.DOM.currentDocument(), arguments);
+ },
+
+ __new__: function () {
+ this.$$ = this.findDocElements;
+ MochiKit.Base.nameFunctions(this);
+ }
+});
+
+MochiKit.Selector.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.Selector);
diff --git a/frontend/delta/js/MochiKit/Signal.js b/frontend/delta/js/MochiKit/Signal.js
new file mode 100644
index 0000000..58d0363
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Signal.js
@@ -0,0 +1,924 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Signal 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2006 Jonathan Gardner, Beau Hartshorne, Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Signal', '1.5', ['Base', 'DOM']);
+
+MochiKit.Signal._observers = [];
+
+/** @id MochiKit.Signal.Event */
+MochiKit.Signal.Event = function (src, e) {
+ this._event = e || window.event;
+ this._src = src;
+};
+MochiKit.Signal.Event.__export__ = false;
+
+MochiKit.Base.update(MochiKit.Signal.Event.prototype, {
+
+ __repr__: function () {
+ var repr = MochiKit.Base.repr;
+ var str = '{event(): ' + repr(this.event()) +
+ ', src(): ' + repr(this.src()) +
+ ', type(): ' + repr(this.type()) +
+ ', target(): ' + repr(this.target());
+
+ if (this.type() &&
+ this.type().indexOf('key') === 0 ||
+ this.type().indexOf('mouse') === 0 ||
+ this.type().indexOf('click') != -1 ||
+ this.type() == 'contextmenu') {
+ str += ', modifier(): ' + '{alt: ' + repr(this.modifier().alt) +
+ ', ctrl: ' + repr(this.modifier().ctrl) +
+ ', meta: ' + repr(this.modifier().meta) +
+ ', shift: ' + repr(this.modifier().shift) +
+ ', any: ' + repr(this.modifier().any) + '}';
+ }
+
+ if (this.type() && this.type().indexOf('key') === 0) {
+ str += ', key(): {code: ' + repr(this.key().code) +
+ ', string: ' + repr(this.key().string) + '}';
+ }
+
+ if (this.type() && (
+ this.type().indexOf('mouse') === 0 ||
+ this.type().indexOf('click') != -1 ||
+ this.type() == 'contextmenu')) {
+
+ str += ', mouse(): {page: ' + repr(this.mouse().page) +
+ ', client: ' + repr(this.mouse().client);
+
+ if (this.type() != 'mousemove' && this.type() != 'mousewheel') {
+ str += ', button: {left: ' + repr(this.mouse().button.left) +
+ ', middle: ' + repr(this.mouse().button.middle) +
+ ', right: ' + repr(this.mouse().button.right) + '}';
+ }
+ if (this.type() == 'mousewheel') {
+ str += ', wheel: ' + repr(this.mouse().wheel);
+ }
+ str += '}';
+ }
+ if (this.type() == 'mouseover' || this.type() == 'mouseout' ||
+ this.type() == 'mouseenter' || this.type() == 'mouseleave') {
+ str += ', relatedTarget(): ' + repr(this.relatedTarget());
+ }
+ str += '}';
+ return str;
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.toString */
+ toString: function () {
+ return this.__repr__();
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.src */
+ src: function () {
+ return this._src;
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.event */
+ event: function () {
+ return this._event;
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.type */
+ type: function () {
+ if (this._event.type === "DOMMouseScroll") {
+ return "mousewheel";
+ } else {
+ return this._event.type || undefined;
+ }
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.target */
+ target: function () {
+ return this._event.target || this._event.srcElement;
+ },
+
+ _relatedTarget: null,
+ /** @id MochiKit.Signal.Event.prototype.relatedTarget */
+ relatedTarget: function () {
+ if (this._relatedTarget !== null) {
+ return this._relatedTarget;
+ }
+
+ var elem = null;
+ if (this.type() == 'mouseover' || this.type() == 'mouseenter') {
+ elem = (this._event.relatedTarget ||
+ this._event.fromElement);
+ } else if (this.type() == 'mouseout' || this.type() == 'mouseleave') {
+ elem = (this._event.relatedTarget ||
+ this._event.toElement);
+ }
+ try {
+ if (elem !== null && elem.nodeType !== null) {
+ this._relatedTarget = elem;
+ return elem;
+ }
+ } catch (ignore) {
+ // Firefox 3 throws a permission denied error when accessing
+ // any property on XUL elements (e.g. scrollbars)...
+ }
+
+ return undefined;
+ },
+
+ _modifier: null,
+ /** @id MochiKit.Signal.Event.prototype.modifier */
+ modifier: function () {
+ if (this._modifier !== null) {
+ return this._modifier;
+ }
+ var m = {};
+ m.alt = this._event.altKey;
+ m.ctrl = this._event.ctrlKey;
+ m.meta = this._event.metaKey || false; // IE and Opera punt here
+ m.shift = this._event.shiftKey;
+ m.any = m.alt || m.ctrl || m.shift || m.meta;
+ this._modifier = m;
+ return m;
+ },
+
+ _key: null,
+ /** @id MochiKit.Signal.Event.prototype.key */
+ key: function () {
+ if (this._key !== null) {
+ return this._key;
+ }
+ var k = {};
+ if (this.type() && this.type().indexOf('key') === 0) {
+
+ /*
+
+ If you're looking for a special key, look for it in keydown or
+ keyup, but never keypress. If you're looking for a Unicode
+ chracter, look for it with keypress, but never keyup or
+ keydown.
+
+ Notes:
+
+ FF key event behavior:
+ key event charCode keyCode
+ DOWN ku,kd 0 40
+ DOWN kp 0 40
+ ESC ku,kd 0 27
+ ESC kp 0 27
+ a ku,kd 0 65
+ a kp 97 0
+ shift+a ku,kd 0 65
+ shift+a kp 65 0
+ 1 ku,kd 0 49
+ 1 kp 49 0
+ shift+1 ku,kd 0 0
+ shift+1 kp 33 0
+
+ IE key event behavior:
+ (IE doesn't fire keypress events for special keys.)
+ key event keyCode
+ DOWN ku,kd 40
+ DOWN kp undefined
+ ESC ku,kd 27
+ ESC kp 27
+ a ku,kd 65
+ a kp 97
+ shift+a ku,kd 65
+ shift+a kp 65
+ 1 ku,kd 49
+ 1 kp 49
+ shift+1 ku,kd 49
+ shift+1 kp 33
+
+ Safari key event behavior:
+ (Safari sets charCode and keyCode to something crazy for
+ special keys.)
+ key event charCode keyCode
+ DOWN ku,kd 63233 40
+ DOWN kp 63233 63233
+ ESC ku,kd 27 27
+ ESC kp 27 27
+ a ku,kd 97 65
+ a kp 97 97
+ shift+a ku,kd 65 65
+ shift+a kp 65 65
+ 1 ku,kd 49 49
+ 1 kp 49 49
+ shift+1 ku,kd 33 49
+ shift+1 kp 33 33
+
+ */
+
+ /* look for special keys here */
+ if (this.type() == 'keydown' || this.type() == 'keyup') {
+ k.code = this._event.keyCode;
+ k.string = (MochiKit.Signal._specialKeys[k.code] ||
+ 'KEY_UNKNOWN');
+ this._key = k;
+ return k;
+
+ /* look for characters here */
+ } else if (this.type() == 'keypress') {
+
+ /*
+
+ Special key behavior:
+
+ IE: does not fire keypress events for special keys
+ FF: sets charCode to 0, and sets the correct keyCode
+ Safari: sets keyCode and charCode to something stupid
+
+ */
+
+ k.code = 0;
+ k.string = '';
+
+ if (typeof(this._event.charCode) != 'undefined' &&
+ this._event.charCode !== 0 &&
+ !MochiKit.Signal._specialMacKeys[this._event.charCode]) {
+ k.code = this._event.charCode;
+ k.string = String.fromCharCode(k.code);
+ } else if (this._event.keyCode &&
+ typeof(this._event.charCode) == 'undefined') { // IE
+ k.code = this._event.keyCode;
+ k.string = String.fromCharCode(k.code);
+ }
+
+ this._key = k;
+ return k;
+ }
+ }
+ return undefined;
+ },
+
+ _mouse: null,
+ /** @id MochiKit.Signal.Event.prototype.mouse */
+ mouse: function () {
+ if (this._mouse !== null) {
+ return this._mouse;
+ }
+
+ var m = {};
+ var e = this._event;
+
+ if (this.type() && (
+ this.type().indexOf('mouse') === 0 ||
+ this.type().indexOf('drag') === 0 ||
+ this.type().indexOf('click') != -1 ||
+ this.type() == 'contextmenu')) {
+
+ m.client = { x: 0, y: 0 };
+ if (e.clientX || e.clientY) {
+ m.client.x = (!e.clientX || e.clientX < 0) ? 0 : e.clientX;
+ m.client.y = (!e.clientY || e.clientY < 0) ? 0 : e.clientY;
+ }
+
+ m.page = { x: 0, y: 0 };
+ if (e.pageX || e.pageY) {
+ m.page.x = (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
+ m.page.y = (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
+ } else {
+ /*
+
+ The IE shortcut can be off by two. We fix it. See:
+ http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
+
+ This is similar to the method used in
+ MochiKit.Style.getElementPosition().
+
+ */
+ var de = MochiKit.DOM._document.documentElement;
+ var b = MochiKit.DOM._document.body;
+
+ m.page.x = e.clientX +
+ (de.scrollLeft || b.scrollLeft) -
+ (de.clientLeft || 0);
+
+ m.page.y = e.clientY +
+ (de.scrollTop || b.scrollTop) -
+ (de.clientTop || 0);
+
+ }
+ if (this.type() != 'mousemove' && this.type() != 'mousewheel') {
+ m.button = {};
+ m.button.left = false;
+ m.button.right = false;
+ m.button.middle = false;
+
+ /* we could check e.button, but which is more consistent */
+ if (e.which) {
+ m.button.left = (e.which == 1);
+ m.button.middle = (e.which == 2);
+ m.button.right = (e.which == 3);
+
+ /*
+
+ Mac browsers and right click:
+
+ - Safari doesn't fire any click events on a right
+ click:
+ http://bugs.webkit.org/show_bug.cgi?id=6595
+
+ - Firefox fires the event, and sets ctrlKey = true
+
+ - Opera fires the event, and sets metaKey = true
+
+ oncontextmenu is fired on right clicks between
+ browsers and across platforms.
+
+ */
+
+ } else {
+ m.button.left = !!(e.button & 1);
+ m.button.right = !!(e.button & 2);
+ m.button.middle = !!(e.button & 4);
+ }
+ }
+ if (this.type() == 'mousewheel') {
+ m.wheel = { x: 0, y: 0 };
+ if (e.wheelDeltaX || e.wheelDeltaY) {
+ m.wheel.x = e.wheelDeltaX / -40 || 0;
+ m.wheel.y = e.wheelDeltaY / -40 || 0;
+ } else if (e.wheelDelta) {
+ m.wheel.y = e.wheelDelta / -40;
+ } else {
+ m.wheel.y = e.detail || 0;
+ }
+ }
+ this._mouse = m;
+ return m;
+ }
+ return undefined;
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.stop */
+ stop: function () {
+ this.stopPropagation();
+ this.preventDefault();
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.stopPropagation */
+ stopPropagation: function () {
+ if (this._event.stopPropagation) {
+ this._event.stopPropagation();
+ } else {
+ this._event.cancelBubble = true;
+ }
+ },
+
+ /** @id MochiKit.Signal.Event.prototype.preventDefault */
+ preventDefault: function () {
+ if (this._event.preventDefault) {
+ this._event.preventDefault();
+ } else if (this._confirmUnload === null) {
+ this._event.returnValue = false;
+ }
+ },
+
+ _confirmUnload: null,
+
+ /** @id MochiKit.Signal.Event.prototype.confirmUnload */
+ confirmUnload: function (msg) {
+ if (this.type() == 'beforeunload') {
+ this._confirmUnload = msg;
+ this._event.returnValue = msg;
+ }
+ }
+});
+
+/* Safari sets keyCode to these special values onkeypress. */
+MochiKit.Signal._specialMacKeys = {
+ 3: 'KEY_ENTER',
+ 63289: 'KEY_NUM_PAD_CLEAR',
+ 63276: 'KEY_PAGE_UP',
+ 63277: 'KEY_PAGE_DOWN',
+ 63275: 'KEY_END',
+ 63273: 'KEY_HOME',
+ 63234: 'KEY_ARROW_LEFT',
+ 63232: 'KEY_ARROW_UP',
+ 63235: 'KEY_ARROW_RIGHT',
+ 63233: 'KEY_ARROW_DOWN',
+ 63302: 'KEY_INSERT',
+ 63272: 'KEY_DELETE'
+};
+
+/* for KEY_F1 - KEY_F12 */
+(function () {
+ var _specialMacKeys = MochiKit.Signal._specialMacKeys;
+ for (var i = 63236; i <= 63242; i++) {
+ // no F0
+ _specialMacKeys[i] = 'KEY_F' + (i - 63236 + 1);
+ }
+})();
+
+/* Standard keyboard key codes. */
+MochiKit.Signal._specialKeys = {
+ 8: 'KEY_BACKSPACE',
+ 9: 'KEY_TAB',
+ 12: 'KEY_NUM_PAD_CLEAR', // weird, for Safari and Mac FF only
+ 13: 'KEY_ENTER',
+ 16: 'KEY_SHIFT',
+ 17: 'KEY_CTRL',
+ 18: 'KEY_ALT',
+ 19: 'KEY_PAUSE',
+ 20: 'KEY_CAPS_LOCK',
+ 27: 'KEY_ESCAPE',
+ 32: 'KEY_SPACEBAR',
+ 33: 'KEY_PAGE_UP',
+ 34: 'KEY_PAGE_DOWN',
+ 35: 'KEY_END',
+ 36: 'KEY_HOME',
+ 37: 'KEY_ARROW_LEFT',
+ 38: 'KEY_ARROW_UP',
+ 39: 'KEY_ARROW_RIGHT',
+ 40: 'KEY_ARROW_DOWN',
+ 44: 'KEY_PRINT_SCREEN',
+ 45: 'KEY_INSERT',
+ 46: 'KEY_DELETE',
+ 59: 'KEY_SEMICOLON', // weird, for Safari and IE only
+ 91: 'KEY_WINDOWS_LEFT',
+ 92: 'KEY_WINDOWS_RIGHT',
+ 93: 'KEY_SELECT',
+ 106: 'KEY_NUM_PAD_ASTERISK',
+ 107: 'KEY_NUM_PAD_PLUS_SIGN',
+ 109: 'KEY_NUM_PAD_HYPHEN-MINUS',
+ 110: 'KEY_NUM_PAD_FULL_STOP',
+ 111: 'KEY_NUM_PAD_SOLIDUS',
+ 144: 'KEY_NUM_LOCK',
+ 145: 'KEY_SCROLL_LOCK',
+ 186: 'KEY_SEMICOLON',
+ 187: 'KEY_EQUALS_SIGN',
+ 188: 'KEY_COMMA',
+ 189: 'KEY_HYPHEN-MINUS',
+ 190: 'KEY_FULL_STOP',
+ 191: 'KEY_SOLIDUS',
+ 192: 'KEY_GRAVE_ACCENT',
+ 219: 'KEY_LEFT_SQUARE_BRACKET',
+ 220: 'KEY_REVERSE_SOLIDUS',
+ 221: 'KEY_RIGHT_SQUARE_BRACKET',
+ 222: 'KEY_APOSTROPHE'
+ // undefined: 'KEY_UNKNOWN'
+};
+
+(function () {
+ /* for KEY_0 - KEY_9 */
+ var _specialKeys = MochiKit.Signal._specialKeys;
+ for (var i = 48; i <= 57; i++) {
+ _specialKeys[i] = 'KEY_' + (i - 48);
+ }
+
+ /* for KEY_A - KEY_Z */
+ for (i = 65; i <= 90; i++) {
+ _specialKeys[i] = 'KEY_' + String.fromCharCode(i);
+ }
+
+ /* for KEY_NUM_PAD_0 - KEY_NUM_PAD_9 */
+ for (i = 96; i <= 105; i++) {
+ _specialKeys[i] = 'KEY_NUM_PAD_' + (i - 96);
+ }
+
+ /* for KEY_F1 - KEY_F12 */
+ for (i = 112; i <= 123; i++) {
+ // no F0
+ _specialKeys[i] = 'KEY_F' + (i - 112 + 1);
+ }
+})();
+
+/* Internal object to keep track of created signals. */
+MochiKit.Signal.Ident = function (ident) {
+ this.source = ident.source;
+ this.signal = ident.signal;
+ this.listener = ident.listener;
+ this.isDOM = ident.isDOM;
+ this.objOrFunc = ident.objOrFunc;
+ this.funcOrStr = ident.funcOrStr;
+ this.connected = ident.connected;
+};
+MochiKit.Signal.Ident.__export__ = false;
+MochiKit.Signal.Ident.prototype = {};
+
+MochiKit.Base.update(MochiKit.Signal, {
+
+ _unloadCache: function () {
+ var self = MochiKit.Signal;
+ var observers = self._observers;
+
+ for (var i = 0; i < observers.length; i++) {
+ if (observers[i].signal !== 'onload' && observers[i].signal !== 'onunload') {
+ self._disconnect(observers[i]);
+ }
+ }
+ },
+
+ _listener: function (src, sig, func, obj, isDOM) {
+ var self = MochiKit.Signal;
+ var E = self.Event;
+ if (!isDOM) {
+ /* We don't want to re-bind already bound methods */
+ if (typeof(func.im_self) == 'undefined') {
+ return MochiKit.Base.bindLate(func, obj);
+ } else {
+ return func;
+ }
+ }
+ obj = obj || src;
+ if (typeof(func) == "string") {
+ if (sig === 'onload' || sig === 'onunload') {
+ return function (nativeEvent) {
+ obj[func].apply(obj, [new E(src, nativeEvent)]);
+
+ var ident = new MochiKit.Signal.Ident({
+ source: src, signal: sig, objOrFunc: obj, funcOrStr: func});
+
+ MochiKit.Signal._disconnect(ident);
+ };
+ } else {
+ return function (nativeEvent) {
+ obj[func].apply(obj, [new E(src, nativeEvent)]);
+ };
+ }
+ } else {
+ if (sig === 'onload' || sig === 'onunload') {
+ return function (nativeEvent) {
+ func.apply(obj, [new E(src, nativeEvent)]);
+
+ var ident = new MochiKit.Signal.Ident({
+ source: src, signal: sig, objOrFunc: func});
+
+ MochiKit.Signal._disconnect(ident);
+ };
+ } else {
+ return function (nativeEvent) {
+ func.apply(obj, [new E(src, nativeEvent)]);
+ };
+ }
+ }
+ },
+
+ _browserAlreadyHasMouseEnterAndLeave: function () {
+ return /MSIE/.test(navigator.userAgent);
+ },
+
+ _browserLacksMouseWheelEvent: function () {
+ return /Gecko\//.test(navigator.userAgent);
+ },
+
+ _mouseEnterListener: function (src, sig, func, obj) {
+ var E = MochiKit.Signal.Event;
+ return function (nativeEvent) {
+ var e = new E(src, nativeEvent);
+ try {
+ e.relatedTarget().nodeName;
+ } catch (err) {
+ /* probably hit a permission denied error; possibly one of
+ * firefox's screwy anonymous DIVs inside an input element.
+ * Allow this event to propogate up.
+ */
+ return;
+ }
+ e.stop();
+ if (MochiKit.DOM.isChildNode(e.relatedTarget(), src)) {
+ /* We've moved between our node and a child. Ignore. */
+ return;
+ }
+ e.type = function () { return sig; };
+ if (typeof(func) == "string") {
+ return obj[func].apply(obj, [e]);
+ } else {
+ return func.apply(obj, [e]);
+ }
+ };
+ },
+
+ _getDestPair: function (objOrFunc, funcOrStr) {
+ var obj = null;
+ var func = null;
+ if (typeof(funcOrStr) != 'undefined') {
+ obj = objOrFunc;
+ func = funcOrStr;
+ if (typeof(funcOrStr) == 'string') {
+ if (typeof(objOrFunc[funcOrStr]) != "function") {
+ throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
+ }
+ } else if (typeof(funcOrStr) != 'function') {
+ throw new Error("'funcOrStr' must be a function or string");
+ }
+ } else if (typeof(objOrFunc) != "function") {
+ throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
+ } else {
+ func = objOrFunc;
+ }
+ return [obj, func];
+ },
+
+ /** @id MochiKit.Signal.connect */
+ connect: function (src, sig, objOrFunc/* optional */, funcOrStr) {
+ if (typeof(src) == "string") {
+ src = MochiKit.DOM.getElement(src);
+ }
+ var self = MochiKit.Signal;
+
+ if (typeof(sig) != 'string') {
+ throw new Error("'sig' must be a string");
+ }
+
+ var destPair = self._getDestPair(objOrFunc, funcOrStr);
+ var obj = destPair[0];
+ var func = destPair[1];
+ if (typeof(obj) == 'undefined' || obj === null) {
+ obj = src;
+ }
+
+ var isDOM = !!(src.addEventListener || src.attachEvent);
+ if (isDOM && (sig === "onmouseenter" || sig === "onmouseleave")
+ && !self._browserAlreadyHasMouseEnterAndLeave()) {
+ var listener = self._mouseEnterListener(src, sig.substr(2), func, obj);
+ if (sig === "onmouseenter") {
+ sig = "onmouseover";
+ } else {
+ sig = "onmouseout";
+ }
+ } else if (isDOM && sig == "onmousewheel" && self._browserLacksMouseWheelEvent()) {
+ var listener = self._listener(src, sig, func, obj, isDOM);
+ sig = "onDOMMouseScroll";
+ } else {
+ var listener = self._listener(src, sig, func, obj, isDOM);
+ }
+
+ if (src.addEventListener) {
+ src.addEventListener(sig.substr(2), listener, false);
+ } else if (src.attachEvent) {
+ src.attachEvent(sig, listener); // useCapture unsupported
+ }
+
+ var ident = new MochiKit.Signal.Ident({
+ source: src,
+ signal: sig,
+ listener: listener,
+ isDOM: isDOM,
+ objOrFunc: objOrFunc,
+ funcOrStr: funcOrStr,
+ connected: true
+ });
+ self._observers.push(ident);
+
+ if (!isDOM && typeof(src.__connect__) == 'function') {
+ var args = MochiKit.Base.extend([ident], arguments, 1);
+ src.__connect__.apply(src, args);
+ }
+
+ return ident;
+ },
+
+ /** @id MochiKit.Signal.connectOnce */
+ connectOnce: function (src, sig, objOrFunc/* optional */, funcOrStr) {
+ var self = MochiKit.Signal;
+ var ident1 = self.connect(src, sig, objOrFunc, funcOrStr);
+ var ident2;
+ ident2 = self.connect(src, sig, function() {
+ self.disconnect(ident1);
+ self.disconnect(ident2);
+ });
+ return ident1;
+ },
+
+ _disconnect: function (ident) {
+ // already disconnected
+ if (!ident.connected) {
+ return;
+ }
+ ident.connected = false;
+ var src = ident.source;
+ var sig = ident.signal;
+ var listener = ident.listener;
+ // check isDOM
+ if (!ident.isDOM) {
+ if (typeof(src.__disconnect__) == 'function') {
+ src.__disconnect__(ident, sig, ident.objOrFunc, ident.funcOrStr);
+ }
+ return;
+ }
+ if (src.removeEventListener) {
+ src.removeEventListener(sig.substr(2), listener, false);
+ } else if (src.detachEvent) {
+ src.detachEvent(sig, listener); // useCapture unsupported
+ } else {
+ throw new Error("'src' must be a DOM element");
+ }
+ },
+
+ /** @id MochiKit.Signal.disconnect */
+ disconnect: function (ident) {
+ var self = MochiKit.Signal;
+ var observers = self._observers;
+ var m = MochiKit.Base;
+ if (arguments.length > 1) {
+ // compatibility API
+ var src = arguments[0];
+ if (typeof(src) == "string") {
+ src = MochiKit.DOM.getElement(src);
+ }
+ var sig = arguments[1];
+ var obj = arguments[2];
+ var func = arguments[3];
+ for (var i = observers.length - 1; i >= 0; i--) {
+ var o = observers[i];
+ if (o.source === src && o.signal === sig && o.objOrFunc === obj && o.funcOrStr === func) {
+ self._disconnect(o);
+ if (self._lock === 0) {
+ observers.splice(i, 1);
+ } else {
+ self._dirty = true;
+ }
+ return true;
+ }
+ }
+ } else {
+ var idx = m.findIdentical(observers, ident);
+ if (idx >= 0) {
+ self._disconnect(ident);
+ if (self._lock === 0) {
+ observers.splice(idx, 1);
+ } else {
+ self._dirty = true;
+ }
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /** @id MochiKit.Signal.disconnectAllTo */
+ disconnectAllTo: function (objOrFunc, /* optional */funcOrStr) {
+ var self = MochiKit.Signal;
+ var observers = self._observers;
+ var disconnect = self._disconnect;
+ var lock = self._lock;
+ var dirty = self._dirty;
+ if (typeof(funcOrStr) === 'undefined') {
+ funcOrStr = null;
+ }
+ for (var i = observers.length - 1; i >= 0; i--) {
+ var ident = observers[i];
+ if (ident.objOrFunc === objOrFunc &&
+ (funcOrStr === null || ident.funcOrStr === funcOrStr)) {
+ disconnect(ident);
+ if (lock === 0) {
+ observers.splice(i, 1);
+ } else {
+ dirty = true;
+ }
+ }
+ }
+ self._dirty = dirty;
+ },
+
+ /** @id MochiKit.Signal.disconnectAll */
+ disconnectAll: function (src/* optional */, sig) {
+ if (typeof(src) == "string") {
+ src = MochiKit.DOM.getElement(src);
+ }
+ var m = MochiKit.Base;
+ var signals = m.flattenArguments(m.extend(null, arguments, 1));
+ var self = MochiKit.Signal;
+ var disconnect = self._disconnect;
+ var observers = self._observers;
+ var i, ident;
+ var lock = self._lock;
+ var dirty = self._dirty;
+ if (signals.length === 0) {
+ // disconnect all
+ for (i = observers.length - 1; i >= 0; i--) {
+ ident = observers[i];
+ if (ident.source === src) {
+ disconnect(ident);
+ if (lock === 0) {
+ observers.splice(i, 1);
+ } else {
+ dirty = true;
+ }
+ }
+ }
+ } else {
+ var sigs = {};
+ for (i = 0; i < signals.length; i++) {
+ sigs[signals[i]] = true;
+ }
+ for (i = observers.length - 1; i >= 0; i--) {
+ ident = observers[i];
+ if (ident.source === src && ident.signal in sigs) {
+ disconnect(ident);
+ if (lock === 0) {
+ observers.splice(i, 1);
+ } else {
+ dirty = true;
+ }
+ }
+ }
+ }
+ self._dirty = dirty;
+ },
+
+ /** @id MochiKit.Signal.signal */
+ signal: function (src, sig) {
+ var self = MochiKit.Signal;
+ var observers = self._observers;
+ if (typeof(src) == "string") {
+ src = MochiKit.DOM.getElement(src);
+ }
+ var args = MochiKit.Base.extend(null, arguments, 2);
+ var errors = [];
+ self._lock++;
+ for (var i = 0; i < observers.length; i++) {
+ var ident = observers[i];
+ if (ident.source === src && ident.signal === sig &&
+ ident.connected) {
+ try {
+ if (ident.isDOM && ident.funcOrStr != null) {
+ var obj = ident.objOrFunc;
+ obj[ident.funcOrStr].apply(obj, args);
+ } else if (ident.isDOM) {
+ ident.objOrFunc.apply(src, args);
+ } else {
+ ident.listener.apply(src, args);
+ }
+ } catch (e) {
+ errors.push(e);
+ }
+ }
+ }
+ self._lock--;
+ if (self._lock === 0 && self._dirty) {
+ self._dirty = false;
+ for (var i = observers.length - 1; i >= 0; i--) {
+ if (!observers[i].connected) {
+ observers.splice(i, 1);
+ }
+ }
+ }
+ if (errors.length == 1) {
+ throw errors[0];
+ } else if (errors.length > 1) {
+ var e = new Error("Multiple errors thrown in handling 'sig', see errors property");
+ e.errors = errors;
+ throw e;
+ }
+ }
+
+});
+
+MochiKit.Signal.__new__ = function (win) {
+ var m = MochiKit.Base;
+ this._document = document;
+ this._window = win;
+ this._lock = 0;
+ this._dirty = false;
+
+ try {
+ this.connect(window, 'onunload', this._unloadCache);
+ } catch (e) {
+ // pass: might not be a browser
+ }
+
+ m.nameFunctions(this);
+};
+
+MochiKit.Signal.__new__(this);
+
+//
+// XXX: Internet Explorer blows
+//
+if (MochiKit.__export__) {
+ connect = MochiKit.Signal.connect;
+ disconnect = MochiKit.Signal.disconnect;
+ disconnectAll = MochiKit.Signal.disconnectAll;
+ signal = MochiKit.Signal.signal;
+}
+
+MochiKit.Base._exportSymbols(this, MochiKit.Signal);
diff --git a/frontend/delta/js/MochiKit/Sortable.js b/frontend/delta/js/MochiKit/Sortable.js
new file mode 100644
index 0000000..49ea390
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Sortable.js
@@ -0,0 +1,592 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+ Mochi-ized By Thomas Herve (_firstname_@nimail.org)
+
+See scriptaculous.js for full license.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Sortable', '1.5', ['Base', 'Iter', 'DOM', 'Position', 'DragAndDrop']);
+
+MochiKit.Base.update(MochiKit.Sortable, {
+ __export__: false,
+
+ /***
+
+ Manage sortables. Mainly use the create function to add a sortable.
+
+ ***/
+ sortables: {},
+
+ _findRootElement: function (element) {
+ while (element.tagName.toUpperCase() != "BODY") {
+ if (element.id && MochiKit.Sortable.sortables[element.id]) {
+ return element;
+ }
+ element = element.parentNode;
+ }
+ },
+
+ _createElementId: function(element) {
+ if (element.id == null || element.id == "") {
+ var d = MochiKit.DOM;
+ var id;
+ var count = 1;
+ while (d.getElement(id = "sortable" + count) != null) {
+ count += 1;
+ }
+ d.setNodeAttribute(element, "id", id);
+ }
+ },
+
+ /** @id MochiKit.Sortable.options */
+ options: function (element) {
+ element = MochiKit.Sortable._findRootElement(MochiKit.DOM.getElement(element));
+ if (!element) {
+ return;
+ }
+ return MochiKit.Sortable.sortables[element.id];
+ },
+
+ /** @id MochiKit.Sortable.destroy */
+ destroy: function (element){
+ var s = MochiKit.Sortable.options(element);
+ var b = MochiKit.Base;
+ var d = MochiKit.DragAndDrop;
+
+ if (s) {
+ MochiKit.Signal.disconnect(s.startHandle);
+ MochiKit.Signal.disconnect(s.endHandle);
+ b.map(function (dr) {
+ d.Droppables.remove(dr);
+ }, s.droppables);
+ b.map(function (dr) {
+ dr.destroy();
+ }, s.draggables);
+
+ delete MochiKit.Sortable.sortables[s.element.id];
+ }
+ },
+
+ /** @id MochiKit.Sortable.create */
+ create: function (element, options) {
+ element = MochiKit.DOM.getElement(element);
+ var self = MochiKit.Sortable;
+ self._createElementId(element);
+
+ /** @id MochiKit.Sortable.options */
+ options = MochiKit.Base.update({
+
+ /** @id MochiKit.Sortable.element */
+ element: element,
+
+ /** @id MochiKit.Sortable.tag */
+ tag: 'li', // assumes li children, override with tag: 'tagname'
+
+ /** @id MochiKit.Sortable.dropOnEmpty */
+ dropOnEmpty: false,
+
+ /** @id MochiKit.Sortable.tree */
+ tree: false,
+
+ /** @id MochiKit.Sortable.treeTag */
+ treeTag: 'ul',
+
+ /** @id MochiKit.Sortable.overlap */
+ overlap: 'vertical', // one of 'vertical', 'horizontal'
+
+ /** @id MochiKit.Sortable.constraint */
+ constraint: 'vertical', // one of 'vertical', 'horizontal', false
+ // also takes array of elements (or ids); or false
+
+ /** @id MochiKit.Sortable.containment */
+ containment: [element],
+
+ /** @id MochiKit.Sortable.handle */
+ handle: false, // or a CSS class
+
+ /** @id MochiKit.Sortable.only */
+ only: false,
+
+ /** @id MochiKit.Sortable.hoverclass */
+ hoverclass: null,
+
+ /** @id MochiKit.Sortable.ghosting */
+ ghosting: false,
+
+ /** @id MochiKit.Sortable.scroll */
+ scroll: false,
+
+ /** @id MochiKit.Sortable.scrollSensitivity */
+ scrollSensitivity: 20,
+
+ /** @id MochiKit.Sortable.scrollSpeed */
+ scrollSpeed: 15,
+
+ /** @id MochiKit.Sortable.format */
+ format: /^[^_]*_(.*)$/,
+
+ /** @id MochiKit.Sortable.onChange */
+ onChange: MochiKit.Base.noop,
+
+ /** @id MochiKit.Sortable.onUpdate */
+ onUpdate: MochiKit.Base.noop,
+
+ /** @id MochiKit.Sortable.accept */
+ accept: null
+ }, options);
+
+ // clear any old sortable with same element
+ self.destroy(element);
+
+ // build options for the draggables
+ var options_for_draggable = {
+ revert: true,
+ ghosting: options.ghosting,
+ scroll: options.scroll,
+ scrollSensitivity: options.scrollSensitivity,
+ scrollSpeed: options.scrollSpeed,
+ constraint: options.constraint,
+ handle: options.handle
+ };
+
+ if (options.starteffect) {
+ options_for_draggable.starteffect = options.starteffect;
+ }
+
+ if (options.reverteffect) {
+ options_for_draggable.reverteffect = options.reverteffect;
+ } else if (options.ghosting) {
+ options_for_draggable.reverteffect = function (innerelement) {
+ innerelement.style.top = 0;
+ innerelement.style.left = 0;
+ };
+ }
+
+ if (options.endeffect) {
+ options_for_draggable.endeffect = options.endeffect;
+ }
+
+ if (options.zindex) {
+ options_for_draggable.zindex = options.zindex;
+ }
+
+ // build options for the droppables
+ var options_for_droppable = {
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass,
+ onhover: self.onHover,
+ tree: options.tree,
+ accept: options.accept
+ };
+
+ var options_for_tree = {
+ onhover: self.onEmptyHover,
+ overlap: options.overlap,
+ containment: options.containment,
+ hoverclass: options.hoverclass,
+ accept: options.accept
+ };
+
+ // fix for gecko engine
+ MochiKit.DOM.removeEmptyTextNodes(element);
+
+ options.draggables = [];
+ options.droppables = [];
+
+ // drop on empty handling
+ if (options.dropOnEmpty || options.tree) {
+ new MochiKit.DragAndDrop.Droppable(element, options_for_tree);
+ options.droppables.push(element);
+ }
+ MochiKit.Base.map(function (e) {
+ // handles are per-draggable
+ var handle = options.handle ?
+ MochiKit.DOM.getFirstElementByTagAndClassName(null,
+ options.handle, e) : e;
+ options.draggables.push(
+ new MochiKit.DragAndDrop.Draggable(e,
+ MochiKit.Base.update(options_for_draggable,
+ {handle: handle})));
+ new MochiKit.DragAndDrop.Droppable(e, options_for_droppable);
+ if (options.tree) {
+ e.treeNode = element;
+ }
+ options.droppables.push(e);
+ }, (self.findElements(element, options) || []));
+
+ if (options.tree) {
+ MochiKit.Base.map(function (e) {
+ new MochiKit.DragAndDrop.Droppable(e, options_for_tree);
+ e.treeNode = element;
+ options.droppables.push(e);
+ }, (self.findTreeElements(element, options) || []));
+ }
+
+ // keep reference
+ self.sortables[element.id] = options;
+
+ options.lastValue = self.serialize(element);
+ options.startHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'start',
+ MochiKit.Base.partial(self.onStart, element));
+ options.endHandle = MochiKit.Signal.connect(MochiKit.DragAndDrop.Draggables, 'end',
+ MochiKit.Base.partial(self.onEnd, element));
+ },
+
+ /** @id MochiKit.Sortable.onStart */
+ onStart: function (element, draggable) {
+ var self = MochiKit.Sortable;
+ var options = self.options(element);
+ options.lastValue = self.serialize(options.element);
+ },
+
+ /** @id MochiKit.Sortable.onEnd */
+ onEnd: function (element, draggable) {
+ var self = MochiKit.Sortable;
+ self.unmark();
+ var options = self.options(element);
+ if (options.lastValue != self.serialize(options.element)) {
+ options.onUpdate(options.element);
+ }
+ },
+
+ // return all suitable-for-sortable elements in a guaranteed order
+
+ /** @id MochiKit.Sortable.findElements */
+ findElements: function (element, options) {
+ return MochiKit.Sortable.findChildren(element, options.only, options.tree, options.tag);
+ },
+
+ /** @id MochiKit.Sortable.findTreeElements */
+ findTreeElements: function (element, options) {
+ return MochiKit.Sortable.findChildren(
+ element, options.only, options.tree ? true : false, options.treeTag);
+ },
+
+ /** @id MochiKit.Sortable.findChildren */
+ findChildren: function (element, only, recursive, tagName) {
+ if (!element.hasChildNodes()) {
+ return null;
+ }
+ tagName = tagName.toUpperCase();
+ if (only) {
+ only = MochiKit.Base.flattenArray([only]);
+ }
+ var elements = [];
+ MochiKit.Base.map(function (e) {
+ if (e.tagName &&
+ e.tagName.toUpperCase() == tagName &&
+ (!only ||
+ MochiKit.Iter.some(only, function (c) {
+ return MochiKit.DOM.hasElementClass(e, c);
+ }))) {
+ elements.push(e);
+ }
+ if (recursive) {
+ var grandchildren = MochiKit.Sortable.findChildren(e, only, recursive, tagName);
+ if (grandchildren && grandchildren.length > 0) {
+ elements = elements.concat(grandchildren);
+ }
+ }
+ }, element.childNodes);
+ return elements;
+ },
+
+ /** @id MochiKit.Sortable.onHover */
+ onHover: function (element, dropon, overlap) {
+ if (MochiKit.DOM.isChildNode(dropon, element)) {
+ return;
+ }
+ var self = MochiKit.Sortable;
+
+ if (overlap > .33 && overlap < .66 && self.options(dropon).tree) {
+ return;
+ } else if (overlap > 0.5) {
+ self.mark(dropon, 'before');
+ if (dropon.previousSibling != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = 'hidden'; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, dropon);
+ if (dropon.parentNode != oldParentNode) {
+ self.options(oldParentNode).onChange(element);
+ }
+ self.options(dropon.parentNode).onChange(element);
+ }
+ } else {
+ self.mark(dropon, 'after');
+ var nextElement = dropon.nextSibling || null;
+ if (nextElement != element) {
+ var oldParentNode = element.parentNode;
+ element.style.visibility = 'hidden'; // fix gecko rendering
+ dropon.parentNode.insertBefore(element, nextElement);
+ if (dropon.parentNode != oldParentNode) {
+ self.options(oldParentNode).onChange(element);
+ }
+ self.options(dropon.parentNode).onChange(element);
+ }
+ }
+ },
+
+ _offsetSize: function (element, type) {
+ if (type == 'vertical' || type == 'height') {
+ return element.offsetHeight;
+ } else {
+ return element.offsetWidth;
+ }
+ },
+
+ /** @id MochiKit.Sortable.onEmptyHover */
+ onEmptyHover: function (element, dropon, overlap) {
+ var oldParentNode = element.parentNode;
+ var self = MochiKit.Sortable;
+ var droponOptions = self.options(dropon);
+
+ if (!MochiKit.DOM.isChildNode(dropon, element)) {
+ var index;
+
+ var children = self.findElements(dropon, {tag: droponOptions.tag,
+ only: droponOptions.only});
+ var child = null;
+
+ if (children) {
+ var offset = self._offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
+
+ for (index = 0; index < children.length; index += 1) {
+ if (offset - self._offsetSize(children[index], droponOptions.overlap) >= 0) {
+ offset -= self._offsetSize(children[index], droponOptions.overlap);
+ } else if (offset - (self._offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
+ child = index + 1 < children.length ? children[index + 1] : null;
+ break;
+ } else {
+ child = children[index];
+ break;
+ }
+ }
+ }
+
+ dropon.insertBefore(element, child);
+
+ self.options(oldParentNode).onChange(element);
+ droponOptions.onChange(element);
+ }
+ },
+
+ /** @id MochiKit.Sortable.unmark */
+ unmark: function () {
+ var m = MochiKit.Sortable._marker;
+ if (m) {
+ MochiKit.Style.hideElement(m);
+ }
+ },
+
+ /** @id MochiKit.Sortable.mark */
+ mark: function (dropon, position) {
+ // mark on ghosting only
+ var d = MochiKit.DOM;
+ var self = MochiKit.Sortable;
+ var sortable = self.options(dropon.parentNode);
+ if (sortable && !sortable.ghosting) {
+ return;
+ }
+
+ if (!self._marker) {
+ self._marker = d.getElement('dropmarker') ||
+ document.createElement('DIV');
+ MochiKit.Style.hideElement(self._marker);
+ d.addElementClass(self._marker, 'dropmarker');
+ self._marker.style.position = 'absolute';
+ document.getElementsByTagName('body').item(0).appendChild(self._marker);
+ }
+ var offsets = MochiKit.Position.cumulativeOffset(dropon);
+ self._marker.style.left = offsets.x + 'px';
+ self._marker.style.top = offsets.y + 'px';
+
+ if (position == 'after') {
+ if (sortable.overlap == 'horizontal') {
+ self._marker.style.left = (offsets.x + dropon.clientWidth) + 'px';
+ } else {
+ self._marker.style.top = (offsets.y + dropon.clientHeight) + 'px';
+ }
+ }
+ MochiKit.Style.showElement(self._marker);
+ },
+
+ _tree: function (element, options, parent) {
+ var self = MochiKit.Sortable;
+ var children = self.findElements(element, options) || [];
+
+ for (var i = 0; i < children.length; ++i) {
+ var match = children[i].id.match(options.format);
+
+ if (!match) {
+ continue;
+ }
+
+ var child = {
+ id: encodeURIComponent(match ? match[1] : null),
+ element: element,
+ parent: parent,
+ children: [],
+ position: parent.children.length,
+ container: self._findChildrenElement(children[i], options.treeTag.toUpperCase())
+ };
+
+ /* Get the element containing the children and recurse over it */
+ if (child.container) {
+ self._tree(child.container, options, child);
+ }
+
+ parent.children.push (child);
+ }
+
+ return parent;
+ },
+
+ /* Finds the first element of the given tag type within a parent element.
+ Used for finding the first LI[ST] within a L[IST]I[TEM].*/
+ _findChildrenElement: function (element, containerTag) {
+ if (element && element.hasChildNodes) {
+ containerTag = containerTag.toUpperCase();
+ for (var i = 0; i < element.childNodes.length; ++i) {
+ if (element.childNodes[i].tagName.toUpperCase() == containerTag) {
+ return element.childNodes[i];
+ }
+ }
+ }
+ return null;
+ },
+
+ /** @id MochiKit.Sortable.tree */
+ tree: function (element, options) {
+ element = MochiKit.DOM.getElement(element);
+ var sortableOptions = MochiKit.Sortable.options(element);
+ options = MochiKit.Base.update({
+ tag: sortableOptions.tag,
+ treeTag: sortableOptions.treeTag,
+ only: sortableOptions.only,
+ name: element.id,
+ format: sortableOptions.format
+ }, options || {});
+
+ var root = {
+ id: null,
+ parent: null,
+ children: new Array,
+ container: element,
+ position: 0
+ };
+
+ return MochiKit.Sortable._tree(element, options, root);
+ },
+
+ /**
+ * Specifies the sequence for the Sortable.
+ * @param {Node} element Element to use as the Sortable.
+ * @param {Object} newSequence New sequence to use.
+ * @param {Object} options Options to use fro the Sortable.
+ */
+ setSequence: function (element, newSequence, options) {
+ var self = MochiKit.Sortable;
+ var b = MochiKit.Base;
+ element = MochiKit.DOM.getElement(element);
+ options = b.update(self.options(element), options || {});
+
+ var nodeMap = {};
+ b.map(function (n) {
+ var m = n.id.match(options.format);
+ if (m) {
+ nodeMap[m[1]] = [n, n.parentNode];
+ }
+ n.parentNode.removeChild(n);
+ }, self.findElements(element, options));
+
+ b.map(function (ident) {
+ var n = nodeMap[ident];
+ if (n) {
+ n[1].appendChild(n[0]);
+ delete nodeMap[ident];
+ }
+ }, newSequence);
+ },
+
+ /* Construct a [i] index for a particular node */
+ _constructIndex: function (node) {
+ var index = '';
+ do {
+ if (node.id) {
+ index = '[' + node.position + ']' + index;
+ }
+ } while ((node = node.parent) != null);
+ return index;
+ },
+
+ /** @id MochiKit.Sortable.sequence */
+ sequence: function (element, options) {
+ element = MochiKit.DOM.getElement(element);
+ var self = MochiKit.Sortable;
+ var options = MochiKit.Base.update(self.options(element), options || {});
+
+ return MochiKit.Base.map(function (item) {
+ return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
+ }, MochiKit.DOM.getElement(self.findElements(element, options) || []));
+ },
+
+ /**
+ * Serializes the content of a Sortable. Useful to send this content through a XMLHTTPRequest.
+ * These options override the Sortable options for the serialization only.
+ * @param {Node} element Element to serialize.
+ * @param {Object} options Serialization options.
+ */
+ serialize: function (element, options) {
+ element = MochiKit.DOM.getElement(element);
+ var self = MochiKit.Sortable;
+ options = MochiKit.Base.update(self.options(element), options || {});
+ var name = encodeURIComponent(options.name || element.id);
+
+ if (options.tree) {
+ return MochiKit.Base.flattenArray(MochiKit.Base.map(function (item) {
+ return [name + self._constructIndex(item) + "[id]=" +
+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
+ }, self.tree(element, options).children)).join('&');
+ } else {
+ return MochiKit.Base.map(function (item) {
+ return name + "[]=" + encodeURIComponent(item);
+ }, self.sequence(element, options)).join('&');
+ }
+ }
+});
+
+// trunk compatibility
+MochiKit.Sortable.Sortable = MochiKit.Sortable;
+
+MochiKit.Sortable.__new__ = function () {
+ MochiKit.Base.nameFunctions(this);
+};
+
+MochiKit.Sortable.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.Sortable);
diff --git a/frontend/delta/js/MochiKit/Style.js b/frontend/delta/js/MochiKit/Style.js
new file mode 100644
index 0000000..fa5edbf
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Style.js
@@ -0,0 +1,584 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Style 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005-2006 Bob Ippolito, Beau Hartshorne. All rights Reserved.
+
+The MochiKit.Style.getElementPosition function is adapted from
+YAHOO.util.Dom.getXY v0.9.0. which is copyrighted by Yahoo! Inc.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Style', '1.5', ['Base', 'DOM']);
+
+
+/** @id MochiKit.Style.Dimensions */
+MochiKit.Style.Dimensions = function (w, h) {
+ if (!(this instanceof MochiKit.Style.Dimensions)) {
+ return new MochiKit.Style.Dimensions(w, h);
+ }
+ this.w = w;
+ this.h = h;
+};
+
+MochiKit.Style.Dimensions.prototype.__repr__ = function () {
+ var repr = MochiKit.Base.repr;
+ return '{w: ' + repr(this.w) + ', h: ' + repr(this.h) + '}';
+};
+
+MochiKit.Style.Dimensions.prototype.toString = function () {
+ return this.__repr__();
+};
+
+
+/** @id MochiKit.Style.Coordinates */
+MochiKit.Style.Coordinates = function (x, y) {
+ if (!(this instanceof MochiKit.Style.Coordinates)) {
+ return new MochiKit.Style.Coordinates(x, y);
+ }
+ this.x = x;
+ this.y = y;
+};
+
+MochiKit.Style.Coordinates.prototype.__repr__ = function () {
+ var repr = MochiKit.Base.repr;
+ return '{x: ' + repr(this.x) + ', y: ' + repr(this.y) + '}';
+};
+
+MochiKit.Style.Coordinates.prototype.toString = function () {
+ return this.__repr__();
+};
+
+
+MochiKit.Base.update(MochiKit.Style, {
+
+ /** @id MochiKit.Style.getStyle */
+ getStyle: function (elem, cssProperty) {
+ var dom = MochiKit.DOM;
+ var d = dom._document;
+
+ elem = dom.getElement(elem);
+ cssProperty = MochiKit.Base.camelize(cssProperty);
+
+ if (!elem || elem == d) {
+ return undefined;
+ }
+ if (cssProperty == 'opacity' && typeof(elem.filters) != 'undefined') {
+ var opacity = (MochiKit.Style.getStyle(elem, 'filter') || '').match(/alpha\(opacity=(.*)\)/);
+ if (opacity && opacity[1]) {
+ return parseFloat(opacity[1]) / 100;
+ }
+ return 1.0;
+ }
+ if (cssProperty == 'float' || cssProperty == 'cssFloat' || cssProperty == 'styleFloat') {
+ if (elem.style["float"]) {
+ return elem.style["float"];
+ } else if (elem.style.cssFloat) {
+ return elem.style.cssFloat;
+ } else if (elem.style.styleFloat) {
+ return elem.style.styleFloat;
+ } else {
+ return "none";
+ }
+ }
+ var value = elem.style ? elem.style[cssProperty] : null;
+ if (!value) {
+ if (d.defaultView && d.defaultView.getComputedStyle) {
+ var css = d.defaultView.getComputedStyle(elem, null);
+ cssProperty = cssProperty.replace(/([A-Z])/g, '-$1'
+ ).toLowerCase(); // from dojo.style.toSelectorCase
+ value = css ? css.getPropertyValue(cssProperty) : null;
+ } else if (elem.currentStyle) {
+ value = elem.currentStyle[cssProperty];
+ if (/^\d/.test(value) && !/px$/.test(value) && cssProperty != 'fontWeight') {
+ /* Convert to px using an hack from Dean Edwards */
+ var left = elem.style.left;
+ var rsLeft = elem.runtimeStyle.left;
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ elem.style.left = value || 0;
+ value = elem.style.pixelLeft + "px";
+ elem.style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+ }
+ if (cssProperty == 'opacity') {
+ value = parseFloat(value);
+ }
+
+ if (/Opera/.test(navigator.userAgent) && (MochiKit.Base.findValue(['left', 'top', 'right', 'bottom'], cssProperty) != -1)) {
+ if (MochiKit.Style.getStyle(elem, 'position') == 'static') {
+ value = 'auto';
+ }
+ }
+
+ return value == 'auto' ? null : value;
+ },
+
+ /** @id MochiKit.Style.setStyle */
+ setStyle: function (elem, style) {
+ elem = MochiKit.DOM.getElement(elem);
+ for (var name in style) {
+ switch (name) {
+ case 'opacity':
+ MochiKit.Style.setOpacity(elem, style[name]);
+ break;
+ case 'float':
+ case 'cssFloat':
+ case 'styleFloat':
+ if (typeof(elem.style["float"]) != "undefined") {
+ elem.style["float"] = style[name];
+ } else if (typeof(elem.style.cssFloat) != "undefined") {
+ elem.style.cssFloat = style[name];
+ } else {
+ elem.style.styleFloat = style[name];
+ }
+ break;
+ default:
+ elem.style[MochiKit.Base.camelize(name)] = style[name];
+ }
+ }
+ },
+
+ /** @id MochiKit.Style.setOpacity */
+ setOpacity: function (elem, o) {
+ elem = MochiKit.DOM.getElement(elem);
+ var self = MochiKit.Style;
+ if (o == 1) {
+ var toSet = /Gecko/.test(navigator.userAgent) && !(/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent));
+ elem.style["opacity"] = toSet ? 0.999999 : 1.0;
+ if (/MSIE/.test(navigator.userAgent)) {
+ elem.style['filter'] =
+ self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, '');
+ }
+ } else {
+ if (o < 0.00001) {
+ o = 0;
+ }
+ elem.style["opacity"] = o;
+ if (/MSIE/.test(navigator.userAgent)) {
+ elem.style['filter'] =
+ self.getStyle(elem, 'filter').replace(/alpha\([^\)]*\)/gi, '') + 'alpha(opacity=' + o * 100 + ')';
+ }
+ }
+ },
+
+ /*
+
+ getElementPosition is adapted from YAHOO.util.Dom.getXY v0.9.0.
+ Copyright: Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+ License: BSD, http://developer.yahoo.net/yui/license.txt
+
+ */
+
+ /** @id MochiKit.Style.getElementPosition */
+ getElementPosition: function (elem, /* optional */relativeTo) {
+ var self = MochiKit.Style;
+ var dom = MochiKit.DOM;
+ var isCoordinates = function (o) {
+ return o != null &&
+ o.nodeType == null &&
+ typeof(o.x) == "number" &&
+ typeof(o.y) == "number";
+ };
+
+ if (typeof(elem) == "string") {
+ elem = dom.getElement(elem);
+ }
+ if (elem == null ||
+ (!isCoordinates(elem) && self.getStyle(elem, 'display') == 'none')) {
+ return undefined;
+ }
+
+ var c = new self.Coordinates(0, 0);
+ var box = null;
+ var parent = null;
+
+ var d = MochiKit.DOM._document;
+ var de = d.documentElement;
+ var b = d.body;
+
+ if (isCoordinates(elem)) {
+ /* it's just a MochiKit.Style.Coordinates object */
+ c.x += elem.x || 0;
+ c.y += elem.y || 0;
+ } else if (elem.getBoundingClientRect) { // IE shortcut
+ /*
+
+ The IE shortcut can be off by two. We fix it. See:
+ http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
+
+ This is similar to the method used in
+ MochiKit.Signal.Event.mouse().
+
+ */
+ box = elem.getBoundingClientRect();
+
+ c.x += box.left +
+ (de.scrollLeft || b.scrollLeft) -
+ (de.clientLeft || 0);
+
+ c.y += box.top +
+ (de.scrollTop || b.scrollTop) -
+ (de.clientTop || 0);
+
+ } else if (elem.offsetParent) {
+ c.x += elem.offsetLeft;
+ c.y += elem.offsetTop;
+ parent = elem.offsetParent;
+
+ if (parent != elem) {
+ while (parent) {
+ c.x += parseInt(parent.style.borderLeftWidth, 10) || 0;
+ c.y += parseInt(parent.style.borderTopWidth, 10) || 0;
+ c.x += parent.offsetLeft;
+ c.y += parent.offsetTop;
+ parent = parent.offsetParent;
+ }
+ }
+
+ /*
+
+ Opera < 9 and old Safari (absolute) incorrectly account for
+ body offsetTop and offsetLeft.
+
+ */
+ var ua = navigator.userAgent.toLowerCase();
+ if ((typeof(opera) != 'undefined' &&
+ parseFloat(opera.version()) < 9) ||
+ (ua.indexOf('AppleWebKit') != -1 &&
+ self.getStyle(elem, 'position') == 'absolute')) {
+
+ c.x -= b.offsetLeft;
+ c.y -= b.offsetTop;
+
+ }
+
+ // Adjust position for strange Opera scroll bug
+ if (elem.parentNode) {
+ parent = elem.parentNode;
+ } else {
+ parent = null;
+ }
+ while (parent) {
+ var tagName = parent.tagName.toUpperCase();
+ if (tagName === 'BODY' || tagName === 'HTML') {
+ break;
+ }
+ var disp = self.getStyle(parent, 'display');
+ // Handle strange Opera bug for some display
+ if (disp.search(/^inline|table-row.*$/i)) {
+ c.x -= parent.scrollLeft;
+ c.y -= parent.scrollTop;
+ }
+ if (parent.parentNode) {
+ parent = parent.parentNode;
+ } else {
+ parent = null;
+ }
+ }
+ }
+
+ if (relativeTo) {
+ relativeTo = arguments.callee(relativeTo);
+ if (relativeTo) {
+ c.x -= (relativeTo.x || 0);
+ c.y -= (relativeTo.y || 0);
+ }
+ }
+
+ return c;
+ },
+
+ /** @id MochiKit.Style.setElementPosition */
+ setElementPosition: function (elem, newPos/* optional */, units) {
+ elem = MochiKit.DOM.getElement(elem);
+ if (typeof(units) == 'undefined') {
+ units = 'px';
+ }
+ var newStyle = {};
+ var isUndefNull = MochiKit.Base.isUndefinedOrNull;
+ if (!isUndefNull(newPos.x)) {
+ newStyle['left'] = newPos.x + units;
+ }
+ if (!isUndefNull(newPos.y)) {
+ newStyle['top'] = newPos.y + units;
+ }
+ MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle});
+ },
+
+ /** @id MochiKit.Style.makePositioned */
+ makePositioned: function (element) {
+ element = MochiKit.DOM.getElement(element);
+ var pos = MochiKit.Style.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context,
+ // when an element is position relative but top and left have
+ // not been defined
+ if (/Opera/.test(navigator.userAgent)) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ },
+
+ /** @id MochiKit.Style.undoPositioned */
+ undoPositioned: function (element) {
+ element = MochiKit.DOM.getElement(element);
+ if (element.style.position == 'relative') {
+ element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = '';
+ }
+ },
+
+ /** @id MochiKit.Style.makeClipping */
+ makeClipping: function (element) {
+ element = MochiKit.DOM.getElement(element);
+ var s = element.style;
+ var oldOverflow = { 'overflow': s.overflow,
+ 'overflow-x': s.overflowX,
+ 'overflow-y': s.overflowY };
+ if ((MochiKit.Style.getStyle(element, 'overflow') || 'visible') != 'hidden') {
+ element.style.overflow = 'hidden';
+ element.style.overflowX = 'hidden';
+ element.style.overflowY = 'hidden';
+ }
+ return oldOverflow;
+ },
+
+ /** @id MochiKit.Style.undoClipping */
+ undoClipping: function (element, overflow) {
+ element = MochiKit.DOM.getElement(element);
+ if (typeof(overflow) == 'string') {
+ element.style.overflow = overflow;
+ } else if (overflow != null) {
+ element.style.overflow = overflow['overflow'];
+ element.style.overflowX = overflow['overflow-x'];
+ element.style.overflowY = overflow['overflow-y'];
+ }
+ },
+
+ /** @id MochiKit.Style.getElementDimensions */
+ getElementDimensions: function (elem, contentSize/*optional*/) {
+ var self = MochiKit.Style;
+ var dom = MochiKit.DOM;
+ if (typeof(elem.w) == 'number' || typeof(elem.h) == 'number') {
+ return new self.Dimensions(elem.w || 0, elem.h || 0);
+ }
+ elem = dom.getElement(elem);
+ if (!elem) {
+ return undefined;
+ }
+ var disp = self.getStyle(elem, 'display');
+ // display can be empty/undefined on WebKit/KHTML
+ if (disp == 'none' || disp == '' || typeof(disp) == 'undefined') {
+ var s = elem.style;
+ var originalVisibility = s.visibility;
+ var originalPosition = s.position;
+ var originalDisplay = s.display;
+ s.visibility = 'hidden';
+ s.position = 'absolute';
+ s.display = self._getDefaultDisplay(elem);
+ var originalWidth = elem.offsetWidth;
+ var originalHeight = elem.offsetHeight;
+ s.display = originalDisplay;
+ s.position = originalPosition;
+ s.visibility = originalVisibility;
+ } else {
+ originalWidth = elem.offsetWidth || 0;
+ originalHeight = elem.offsetHeight || 0;
+ }
+ if (contentSize) {
+ var tableCell = 'colSpan' in elem && 'rowSpan' in elem;
+ var collapse = (tableCell && elem.parentNode && self.getStyle(
+ elem.parentNode, 'borderCollapse') == 'collapse');
+ if (collapse) {
+ if (/MSIE/.test(navigator.userAgent)) {
+ var borderLeftQuota = elem.previousSibling? 0.5 : 1;
+ var borderRightQuota = elem.nextSibling? 0.5 : 1;
+ }
+ else {
+ var borderLeftQuota = 0.5;
+ var borderRightQuota = 0.5;
+ }
+ } else {
+ var borderLeftQuota = 1;
+ var borderRightQuota = 1;
+ }
+ originalWidth -= Math.round(
+ (parseFloat(self.getStyle(elem, 'paddingLeft')) || 0)
+ + (parseFloat(self.getStyle(elem, 'paddingRight')) || 0)
+ + borderLeftQuota *
+ (parseFloat(self.getStyle(elem, 'borderLeftWidth')) || 0)
+ + borderRightQuota *
+ (parseFloat(self.getStyle(elem, 'borderRightWidth')) || 0)
+ );
+ if (tableCell) {
+ if (/Gecko|Opera/.test(navigator.userAgent)
+ && !/Konqueror|AppleWebKit|KHTML/.test(navigator.userAgent)) {
+ var borderHeightQuota = 0;
+ } else if (/MSIE/.test(navigator.userAgent)) {
+ var borderHeightQuota = 1;
+ } else {
+ var borderHeightQuota = collapse? 0.5 : 1;
+ }
+ } else {
+ var borderHeightQuota = 1;
+ }
+ originalHeight -= Math.round(
+ (parseFloat(self.getStyle(elem, 'paddingTop')) || 0)
+ + (parseFloat(self.getStyle(elem, 'paddingBottom')) || 0)
+ + borderHeightQuota * (
+ (parseFloat(self.getStyle(elem, 'borderTopWidth')) || 0)
+ + (parseFloat(self.getStyle(elem, 'borderBottomWidth')) || 0))
+ );
+ }
+ return new self.Dimensions(originalWidth, originalHeight);
+ },
+
+ /** @id MochiKit.Style.setElementDimensions */
+ setElementDimensions: function (elem, newSize/* optional */, units) {
+ elem = MochiKit.DOM.getElement(elem);
+ if (typeof(units) == 'undefined') {
+ units = 'px';
+ }
+ var newStyle = {};
+ var isUndefNull = MochiKit.Base.isUndefinedOrNull;
+ if (!isUndefNull(newSize.w)) {
+ newStyle['width'] = newSize.w + units;
+ }
+ if (!isUndefNull(newSize.h)) {
+ newStyle['height'] = newSize.h + units;
+ }
+ MochiKit.DOM.updateNodeAttributes(elem, {'style': newStyle});
+ },
+
+ _getDefaultDisplay: function (elem) {
+ var self = MochiKit.Style;
+ var dom = MochiKit.DOM;
+ elem = dom.getElement(elem);
+ if (!elem) {
+ return undefined;
+ }
+ var tagName = elem.tagName.toUpperCase();
+ return self._defaultDisplay[tagName] || 'block';
+ },
+
+ /** @id MochiKit.Style.setDisplayForElement */
+ setDisplayForElement: function (display, element/*, ...*/) {
+ var elements = MochiKit.Base.extend(null, arguments, 1);
+ var getElement = MochiKit.DOM.getElement;
+ for (var i = 0; i < elements.length; i++) {
+ element = getElement(elements[i]);
+ if (element) {
+ element.style.display = display;
+ }
+ }
+ },
+
+ /** @id MochiKit.Style.getViewportDimensions */
+ getViewportDimensions: function () {
+ var d = new MochiKit.Style.Dimensions();
+ var w = MochiKit.DOM._window;
+ var b = MochiKit.DOM._document.body;
+ if (w.innerWidth) {
+ d.w = w.innerWidth;
+ d.h = w.innerHeight;
+ } else if (b && b.parentElement && b.parentElement.clientWidth) {
+ d.w = b.parentElement.clientWidth;
+ d.h = b.parentElement.clientHeight;
+ } else if (b && b.clientWidth) {
+ d.w = b.clientWidth;
+ d.h = b.clientHeight;
+ }
+ return d;
+ },
+
+ /** @id MochiKit.Style.getViewportPosition */
+ getViewportPosition: function () {
+ var c = new MochiKit.Style.Coordinates(0, 0);
+ var d = MochiKit.DOM._document;
+ var de = d.documentElement;
+ var db = d.body;
+ if (de && (de.scrollTop || de.scrollLeft)) {
+ c.x = de.scrollLeft;
+ c.y = de.scrollTop;
+ } else if (db) {
+ c.x = db.scrollLeft;
+ c.y = db.scrollTop;
+ }
+ return c;
+ },
+
+ __new__: function () {
+ var m = MochiKit.Base;
+
+ var inlines = ['A','ABBR','ACRONYM','B','BASEFONT','BDO','BIG','BR',
+ 'CITE','CODE','DFN','EM','FONT','I','IMG','KBD','LABEL',
+ 'Q','S','SAMP','SMALL','SPAN','STRIKE','STRONG','SUB',
+ 'SUP','TEXTAREA','TT','U','VAR'];
+ this._defaultDisplay = { 'TABLE': 'table',
+ 'THEAD': 'table-header-group',
+ 'TBODY': 'table-row-group',
+ 'TFOOT': 'table-footer-group',
+ 'COLGROUP': 'table-column-group',
+ 'COL': 'table-column',
+ 'TR': 'table-row',
+ 'TD': 'table-cell',
+ 'TH': 'table-cell',
+ 'CAPTION': 'table-caption',
+ 'LI': 'list-item',
+ 'INPUT': 'inline-block',
+ 'SELECT': 'inline-block' };
+ // CSS 'display' support in IE6/7 is just broken...
+ if (/MSIE/.test(navigator.userAgent)) {
+ for (var k in this._defaultDisplay) {
+ var v = this._defaultDisplay[k];
+ if (v.indexOf('table') == 0) {
+ this._defaultDisplay[k] = 'block';
+ }
+ }
+ }
+ for (var i = 0; i < inlines.length; i++) {
+ this._defaultDisplay[inlines[i]] = 'inline';
+ }
+
+ // Backwards compatibility aliases
+ m._deprecated(this, 'elementPosition', 'MochiKit.Style.getElementPosition', '1.3', true);
+ m._deprecated(this, 'elementDimensions', 'MochiKit.Style.getElementDimensions', '1.3', true);
+
+ this.hideElement = m.partial(this.setDisplayForElement, 'none');
+ // TODO: showElement could be improved by using getDefaultDisplay.
+ this.showElement = m.partial(this.setDisplayForElement, 'block');
+
+ m.nameFunctions(this);
+ }
+});
+
+MochiKit.Style.__new__();
+MochiKit.Base._exportSymbols(this, MochiKit.Style);
diff --git a/frontend/delta/js/MochiKit/Test.js b/frontend/delta/js/MochiKit/Test.js
new file mode 100644
index 0000000..55d226c
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Test.js
@@ -0,0 +1,167 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Test 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Test', '1.5', ['Base']);
+
+MochiKit.Test.runTests = function (obj) {
+ if (typeof(obj) == "string") {
+ // TODO: Remove this temporary API change advertisement
+ throw new TypeError("Automatic module import not supported, call runTests() with proper object: " + obj);
+ }
+ var suite = new MochiKit.Test.Suite();
+ suite.run(obj);
+};
+
+MochiKit.Test.Suite = function () {
+ this.testIndex = 0;
+ MochiKit.Base.bindMethods(this);
+};
+
+MochiKit.Test.Suite.prototype = {
+ run: function (obj) {
+ try {
+ obj(this);
+ } catch (e) {
+ this.traceback(e);
+ }
+ },
+ traceback: function (e) {
+ var items = MochiKit.Iter.sorted(MochiKit.Base.items(e));
+ print("not ok " + this.testIndex + " - Error thrown");
+ for (var i = 0; i < items.length; i++) {
+ var kv = items[i];
+ if (kv[0] == "stack") {
+ kv[1] = kv[1].split(/\n/)[0];
+ }
+ this.print("# " + kv.join(": "));
+ }
+ },
+ print: function (s) {
+ print(s);
+ },
+ is: function (got, expected, /* optional */message) {
+ var res = 1;
+ var msg = null;
+ try {
+ res = MochiKit.Base.compare(got, expected);
+ } catch (e) {
+ msg = "Can not compare " + typeof(got) + ":" + typeof(expected);
+ }
+ if (res) {
+ msg = "Expected value did not compare equal";
+ }
+ if (!res) {
+ return this.testResult(true, message);
+ }
+ return this.testResult(false, message,
+ [[msg], ["got:", got], ["expected:", expected]]);
+ },
+
+ testResult: function (pass, msg, failures) {
+ this.testIndex += 1;
+ if (pass) {
+ this.print("ok " + this.testIndex + " - " + msg);
+ return;
+ }
+ this.print("not ok " + this.testIndex + " - " + msg);
+ if (failures) {
+ for (var i = 0; i < failures.length; i++) {
+ this.print("# " + failures[i].join(" "));
+ }
+ }
+ },
+
+ isDeeply: function (got, expected, /* optional */message) {
+ var m = MochiKit.Base;
+ var res = 1;
+ try {
+ res = m.compare(got, expected);
+ } catch (e) {
+ // pass
+ }
+ if (res === 0) {
+ return this.ok(true, message);
+ }
+ var gk = m.keys(got);
+ var ek = m.keys(expected);
+ gk.sort();
+ ek.sort();
+ if (m.compare(gk, ek)) {
+ // differing keys
+ var cmp = {};
+ var i;
+ for (i = 0; i < gk.length; i++) {
+ cmp[gk[i]] = "got";
+ }
+ for (i = 0; i < ek.length; i++) {
+ if (ek[i] in cmp) {
+ delete cmp[ek[i]];
+ } else {
+ cmp[ek[i]] = "expected";
+ }
+ }
+ var diffkeys = m.keys(cmp);
+ diffkeys.sort();
+ var gotkeys = [];
+ var expkeys = [];
+ while (diffkeys.length) {
+ var k = diffkeys.shift();
+ if (k in Object.prototype) {
+ continue;
+ }
+ (cmp[k] == "got" ? gotkeys : expkeys).push(k);
+ }
+
+
+ }
+
+ return this.testResult((!res), msg,
+ (msg ? [["got:", got], ["expected:", expected]] : undefined)
+ );
+ },
+
+ ok: function (res, message) {
+ return this.testResult(res, message);
+ }
+};
+
+MochiKit.Test.__new__ = function () {
+ var m = MochiKit.Base;
+ this.Suite.__export__ = false;
+ m.nameFunctions(this);
+
+};
+
+MochiKit.Test.__new__();
+
+MochiKit.Base._exportSymbols(this, MochiKit.Test);
diff --git a/frontend/delta/js/MochiKit/Text.js b/frontend/delta/js/MochiKit/Text.js
new file mode 100644
index 0000000..0c230fa
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Text.js
@@ -0,0 +1,569 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Text 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2008 Per Cederberg. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Text', '1.5', ['Base', 'Format']);
+
+/**
+ * Checks if a text string starts with the specified substring. If
+ * either of the two strings is null, false will be returned.
+ *
+ * @param {String} substr the substring to search for
+ * @param {String} str the string to search in
+ *
+ * @return {Boolean} true if the string starts with the substring, or
+ * false otherwise
+ */
+MochiKit.Text.startsWith = function (substr, str) {
+ return str != null && substr != null && str.indexOf(substr) == 0;
+};
+
+/**
+ * Checks if a text string ends with the specified substring. If
+ * either of the two strings is null, false will be returned.
+ *
+ * @param {String} substr the substring to search for
+ * @param {String} str the string to search in
+ *
+ * @return {Boolean} true if the string ends with the substring, or
+ * false otherwise
+ */
+MochiKit.Text.endsWith = function (substr, str) {
+ return str != null && substr != null &&
+ str.lastIndexOf(substr) == Math.max(str.length - substr.length, 0);
+};
+
+/**
+ * Checks if a text string contains the specified substring. If
+ * either of the two strings is null, false will be returned.
+ *
+ * @param {String} substr the substring to search for
+ * @param {String} str the string to search in
+ *
+ * @return {Boolean} true if the string contains the substring, or
+ * false otherwise
+ */
+MochiKit.Text.contains = function (substr, str) {
+ return str != null && substr != null && str.indexOf(substr) >= 0;
+};
+
+/**
+ * Adds a character to the left-hand side of a string until it
+ * reaches the specified minimum length.
+ *
+ * @param {String} str the string to process
+ * @param {Number} minLength the requested minimum length
+ * @param {String} fillChar the padding character to add, defaults
+ * to a space
+ *
+ * @return {String} the padded string
+ */
+MochiKit.Text.padLeft = function (str, minLength, fillChar) {
+ str = str || "";
+ fillChar = fillChar || " ";
+ while (str.length < minLength) {
+ str = fillChar + str;
+ }
+ return str;
+};
+
+/**
+ * Adds a character to the right-hand side of a string until it
+ * reaches the specified minimum length.
+ *
+ * @param {String} str the string to process
+ * @param {Number} minLength the requested minimum length
+ * @param {String} fillChar the padding character to add, defaults
+ * to a space
+ *
+ * @return {String} the padded string
+ */
+MochiKit.Text.padRight = function (str, minLength, fillChar) {
+ str = str || "";
+ fillChar = fillChar || " ";
+ while (str.length < minLength) {
+ str += fillChar;
+ }
+ return str;
+};
+
+/**
+ * Returns a truncated copy of a string. If the string is shorter
+ * than the specified maximum length, the object will be returned
+ * unmodified. If an optional tail string is specified, additional
+ * elements will be removed in order to accomodate the tail (that
+ * will be appended). This function also works on arrays.
+ *
+ * @param {String} str the string to truncate
+ * @param {Number} maxLength the maximum length
+ * @param {String} [tail] the tail to append on truncation
+ *
+ * @return {String} the truncated string
+ */
+MochiKit.Text.truncate = function (str, maxLength, tail) {
+ if (str == null || str.length <= maxLength || maxLength < 0) {
+ return str;
+ } else if (tail != null) {
+ str = str.slice(0, Math.max(0, maxLength - tail.length));
+ if (typeof(str) == "string") {
+ return str + tail;
+ } else {
+ return MochiKit.Base.extend(str, tail);
+ }
+ } else {
+ return str.slice(0, maxLength);
+ }
+};
+
+/**
+ * Splits a text string using separator as the split point
+ * If max is given, at most max splits are done, giving at most
+ * max + 1 elements in the returned list.
+ *
+ * @param {String} str the string to split
+ * @param {String/RegExp} [separator] the separator char or regexp to use,
+ * defaults to newline
+ * @param {Number} [max] the maximum number of parts to return
+ * @return {Array} an array of parts of the string
+ */
+MochiKit.Text.split = function (str, separator, max) {
+ if (str == null) {
+ return str;
+ }
+ separator = separator || '\n';
+ var bits = str.split(separator);
+ if ((typeof(max) == "undefined") || max >= bits.length - 1) {
+ return bits;
+ }
+ bits.splice(max, bits.length, bits.slice(max, bits.length).join(separator));
+ return bits;
+};
+
+/**
+ * Splits a text string using separator as the split point
+ * If max is given, at most max splits are done,
+ * using splits from the right
+ *
+ * @param {String} str the string to split
+ * @param {String/RegExp} [separator] the separator char or regexp to use,
+ * defaults to newline
+ * @param {Number} [max] the maximum number of parts to return
+ * @return {Array} an array of parts of the string
+ */
+MochiKit.Text.rsplit = function (str, separator, max) {
+ if (str == null) {
+ return str;
+ }
+ separator = separator || '\n';
+ var bits = str.split(separator);
+ if ((typeof(max) == "undefined") || max >= bits.length - 1){
+ return bits;
+ }
+ bits.splice(0, bits.length-max, bits.slice(0, bits.length-max).join(separator));
+ return bits;
+};
+
+/**
+ * Creates a formatter function for the specified formatter pattern
+ * and locale. The returned function takes as many arguments as the
+ * formatter pattern requires. See separate documentation for
+ * information about the formatter pattern syntax.
+ *
+ * @param {String} pattern the formatter pattern string
+ * @param {Object} [locale] the locale to use, defaults to
+ * LOCALE.en_US
+ *
+ * @return {Function} the formatter function created
+ *
+ * @throws FormatPatternError if the format pattern was invalid
+ */
+MochiKit.Text.formatter = function (pattern, locale) {
+ if (locale == null) {
+ locale = MochiKit.Format.formatLocale();
+ } else if (typeof(locale) == "string") {
+ locale = MochiKit.Format.formatLocale(locale);
+ }
+ var parts = MochiKit.Text._parsePattern(pattern);
+ return function() {
+ var values = MochiKit.Base.extend([], arguments);
+ var res = [];
+ for (var i = 0; i < parts.length; i++) {
+ if (typeof(parts[i]) == "string") {
+ res.push(parts[i]);
+ } else {
+ res.push(MochiKit.Text.formatValue(parts[i], values, locale));
+ }
+ }
+ return res.join("");
+ };
+};
+
+/**
+ * Formats the specified arguments according to a formatter pattern.
+ * See separate documentation for information about the formatter
+ * pattern syntax.
+ *
+ * @param {String} pattern the formatter pattern string
+ * @param {Object} [...] the optional values to format
+ *
+ * @return {String} the formatted output string
+ *
+ * @throws FormatPatternError if the format pattern was invalid
+ */
+MochiKit.Text.format = function (pattern/*, ...*/) {
+ var func = MochiKit.Text.formatter(pattern);
+ return func.apply(this, MochiKit.Base.extend([], arguments, 1));
+};
+
+/**
+ * Format a value with the specified format specifier.
+ *
+ * @param {String/Object} spec the format specifier string or parsed
+ * format specifier object
+ * @param {Object} value the value to format
+ * @param {Object} [locale] the locale to use, defaults to
+ * LOCALE.en_US
+ *
+ * @return {String} the formatted output string
+ *
+ * @throws FormatPatternError if the format specifier was invalid
+ */
+MochiKit.Text.formatValue = function (spec, value, locale) {
+ var self = MochiKit.Text;
+ if (typeof(spec) === "string") {
+ spec = self._parseFormatFlags(spec, 0, spec.length);
+ }
+ for (var i = 0; spec.path != null && i < spec.path.length; i++) {
+ if (value != null) {
+ value = value[spec.path[i]];
+ }
+ }
+ if (locale == null) {
+ locale = MochiKit.Format.formatLocale();
+ } else if (typeof(locale) == "string") {
+ locale = MochiKit.Format.formatLocale(locale);
+ }
+ var str = "";
+ if (spec.type == "number") {
+ if (value instanceof Number) {
+ value = value.valueOf();
+ }
+ if (typeof(value) != "number" || isNaN(value)) {
+ str = "";
+ } else if (value === Number.POSITIVE_INFINITY) {
+ str = "\u221e";
+ } else if (value === Number.NEGATIVE_INFINITY) {
+ str = "-\u221e";
+ } else {
+ var sign = (value < 0) ? "-" : spec.sign;
+ value = Math.abs(value);
+ if (spec.format === "%") {
+ str = self._truncToPercent(value, spec.precision);
+ } else if (spec.format === "d") {
+ str = MochiKit.Format.roundToFixed(value, 0);
+ } else if (spec.radix != 10) {
+ str = Math.floor(value).toString(spec.radix);
+ if (spec.format === "x") {
+ str = str.toLowerCase();
+ } else if (spec.format === "X") {
+ str = str.toUpperCase();
+ }
+ } else if (spec.precision >= 0) {
+ str = MochiKit.Format.roundToFixed(value, spec.precision);
+ } else {
+ str = value.toString();
+ }
+ if (spec.padding === "0" && spec.format === "%") {
+ str = self.padLeft(str, spec.width - sign.length - 1, "0");
+ } else if (spec.padding == "0") {
+ str = self.padLeft(str, spec.width - sign.length, "0");
+ }
+ str = self._localizeNumber(str, locale, spec.group);
+ str = sign + str;
+ }
+ if (str !== "" && spec.format === "%") {
+ str = str + locale.percent;
+ }
+ } else {
+ if (spec.format == "r") {
+ str = MochiKit.Base.repr(value);
+ } else {
+ str = (value == null) ? "" : value.toString();
+ }
+ str = self.truncate(str, spec.precision);
+ }
+ if (spec.align == "<") {
+ str = self.padRight(str, spec.width);
+ } else {
+ str = self.padLeft(str, spec.width);
+ }
+ return str;
+};
+
+/**
+ * Adjust an already formatted numeric string for locale-specific
+ * grouping and decimal separators. The grouping is optional and
+ * will attempt to keep the number string length intact by removing
+ * padded zeros (if possible).
+ *
+ * @param {String} num the formatted number string
+ * @param {Object} locale the formatting locale to use
+ * @param {Boolean} group the grouping flag
+ *
+ * @return {String} the localized number string
+ */
+MochiKit.Text._localizeNumber = function (num, locale, group) {
+ var parts = num.split(/\./);
+ var whole = parts[0];
+ var frac = (parts.length == 1) ? "" : parts[1];
+ var res = (frac.length > 0) ? locale.decimal : "";
+ while (group && frac.length > 3) {
+ res = res + frac.substring(0, 3) + locale.separator;
+ frac = frac.substring(3);
+ if (whole.charAt(0) == "0") {
+ whole = whole.substring(1);
+ }
+ }
+ if (frac.length > 0) {
+ res = res + frac;
+ }
+ while (group && whole.length > 3) {
+ var pos = whole.length - 3;
+ res = locale.separator + whole.substring(pos) + res;
+ whole = whole.substring((whole.charAt(0) == "0") ? 1 : 0, pos);
+ }
+ return whole + res;
+};
+
+/**
+ * Parses a format pattern and returns an array of constant strings
+ * and format info objects.
+ *
+ * @param {String} pattern the format pattern to analyze
+ *
+ * @return {Array} an array of strings and format info objects
+ *
+ * @throws FormatPatternError if the format pattern was invalid
+ */
+MochiKit.Text._parsePattern = function (pattern) {
+ var self = MochiKit.Text;
+ var parts = [];
+ var re = /{[^{}]*}|{{?|}}?/g;
+ var lastPos = re.lastIndex = 0;
+ var m;
+ while ((m = re.exec(pattern)) != null) {
+ if (lastPos < m.index) {
+ parts.push(pattern.substring(lastPos, m.index))
+ }
+ var str = m[0];
+ lastPos = m.index + str.length;
+ if (self.startsWith("{", str) && self.endsWith("}", str)) {
+ parts.push(self._parseFormat(pattern, m.index + 1, lastPos - 1));
+ } else if (self.startsWith("{{", str) || self.startsWith("}}", str)) {
+ parts.push(str.substring(1));
+ } else if (self.startsWith("{", str)) {
+ var msg = "unescaped { char, should be escaped as {{";
+ throw new self.FormatPatternError(pattern, m.index, msg);
+ } else if (self.startsWith("}", str)) {
+ var msg = "unescaped } char, should be escaped as }}";
+ throw new self.FormatPatternError(pattern, m.index, msg);
+ }
+ }
+ if (lastPos < pattern.length) {
+ parts.push(pattern.substring(lastPos));
+ }
+ return parts;
+};
+
+/**
+ * Parses a format instruction and returns a format info object.
+ *
+ * @param {String} pattern the format pattern string
+ * @param {Number} startPos the first index of the format instruction
+ * @param {Number} endPos the last index of the format instruction
+ *
+ * @return {Object} the format info object
+ *
+ * @throws FormatPatternError if the format pattern was invalid
+ */
+MochiKit.Text._parseFormat = function (pattern, startPos, endPos) {
+ var self = MochiKit.Text;
+ var text = pattern.substring(startPos, endPos);
+ var parts = self.split(text, ":", 1);
+ var path = parts[0];
+ var flagsPos = startPos + path.length + ((parts.length == 1) ? 0 : 1);
+ var info = self._parseFormatFlags(pattern, flagsPos, endPos);
+ info.path = (path == "") ? [] : path.split(".");
+ for (var i = 0; i < info.path.length; i++) {
+ var v = info.path[i];
+ // TODO: replace with MochiKit.Format.strip?
+ v = v.replace(/^\s+/, "").replace(/\s+$/, "");
+ if (v == "" && info.path.length == 1) {
+ v = 0;
+ } else if (v == "") {
+ var msg = "format value path contains blanks";
+ throw new self.FormatPatternError(pattern, startPos, msg);
+ } else if (/^\d+$/.test(v)) {
+ v = parseInt(v, 10);
+ }
+ info.path[i] = v;
+ }
+ if (info.path.length <= 0 || typeof(info.path[0]) != "number") {
+ info.path.unshift(0);
+ }
+ return info;
+};
+
+/**
+ * Parses a string with format flags and returns a format info object.
+ *
+ * @param {String} pattern the format pattern string
+ * @param {Number} startPos the first index of the format instruction
+ * @param {Number} endPos the last index of the format instruction
+ *
+ * @return {Object} the format info object
+ *
+ * @throws FormatPatternError if the format pattern was invalid
+ */
+MochiKit.Text._parseFormatFlags = function (pattern, startPos, endPos) {
+ var update = MochiKit.Base.update;
+ var info = { type: "string", format: "s", width: 0, precision: -1,
+ align: ">", sign: "", padding: " ", group: false };
+ // TODO: replace with MochiKit.Format.rstrip?
+ var text = pattern.substring(startPos, endPos).replace(/\s+$/, "");
+ var m = /^([<>+ 0,-]+)?(\d+)?(\.\d*)?([srbdoxXf%])?(.*)$/.exec(text);
+ var flags = m[1];
+ var width = m[2];
+ var precision = m[3];
+ var type = m[4];
+ var unmatched = m[5];
+ for (var i = 0; flags && i < flags.length; i++) {
+ var chr = flags.charAt(i);
+ if (chr == "<" || chr == ">") {
+ info.align = chr;
+ } else if (chr == "+" || chr == "-" || chr == " ") {
+ info.sign = (chr == "-") ? "" : chr;
+ } else if (chr == "0") {
+ info.padding = chr;
+ } else if (chr == ",") {
+ info.group = true;
+ }
+ }
+ if (width) {
+ info.width = parseInt(width, 10);
+ }
+ if (precision && precision.length > 1) {
+ info.precision = parseInt(precision.substring(1), 10);
+ }
+ if (type == "s" || type == "r") {
+ info.format = type;
+ } else if (type == "b") {
+ update(info, { type: "number", format: type, radix: 2 });
+ } else if (type == "o") {
+ update(info, { type: "number", format: type, radix: 8 });
+ } else if (type == "x" || type == "X") {
+ update(info, { type: "number", format: type, radix: 16 });
+ } else if (type == "d" || type == "f" || type == "%") {
+ update(info, { type: "number", format: type, radix: 10 });
+ }
+ if (unmatched) {
+ var msg = "unsupported format flag: " + unmatched.charAt(0);
+ throw new MochiKit.Text.FormatPatternError(pattern, startPos, msg);
+ }
+ return info;
+};
+
+/**
+ * Formats a value as a percentage. This method avoids multiplication
+ * by 100 since it leads to weird numeric rounding errors. Instead it
+ * just move the decimal separator in the text string. It is ugly,
+ * but works...
+ *
+ * @param {Number} value the value to format
+ * @param {Number} precision the number of precision digits
+ */
+MochiKit.Text._truncToPercent = function (value, precision) {
+ // TODO: This can be simplified by using MochiKit.Format._shiftNumber
+ // as roundToFixed does.
+ var str;
+ if (precision >= 0) {
+ str = MochiKit.Format.roundToFixed(value, precision + 2);
+ } else {
+ str = (value == null) ? "0" : value.toString();
+ }
+ var arr = MochiKit.Text.split(str, ".", 2);
+ var frac = MochiKit.Text.padRight(arr[1], 2, "0");
+ var whole = arr[0] + frac.substring(0, 2);
+ frac = frac.substring(2);
+ while (/^0[0-9]/.test(whole)) {
+ whole = whole.substring(1);
+ }
+ return (frac.length <= 0) ? whole : whole + "." + frac;
+};
+
+/**
+ * Creates a new format pattern error.
+ *
+ * @param {String} pattern the format pattern string
+ * @param {Number} pos the position of the error
+ * @param {String} message the error message text
+ *
+ * @return {Error} the format pattern error
+ *
+ * @class The format pattern error class. This error is thrown when
+ * a syntax error is encountered inside a format string.
+ * @property {String} pattern The format pattern string.
+ * @property {Number} pos The position of the error.
+ * @property {String} message The error message text.
+ * @extends MochiKit.Base.NamedError
+ */
+MochiKit.Text.FormatPatternError = function (pattern, pos, message) {
+ this.pattern = pattern;
+ this.pos = pos;
+ this.message = message;
+};
+
+MochiKit.Text.FormatPatternError.prototype = new MochiKit.Base.NamedError("MochiKit.Text.FormatPatternError");
+MochiKit.Text.FormatPatternError.constructor = MochiKit.Text.FormatPatternError;
+
+//
+//XXX: Internet Explorer export fix
+//
+if (MochiKit.__export__) {
+ formatter = MochiKit.Text.formatter;
+ format = MochiKit.Text.format;
+ formatValue = MochiKit.Text.formatValue;
+}
+
+
+MochiKit.Base.nameFunctions(MochiKit.Text);
+MochiKit.Base._exportSymbols(this, MochiKit.Text);
diff --git a/frontend/delta/js/MochiKit/Visual.js b/frontend/delta/js/MochiKit/Visual.js
new file mode 100644
index 0000000..9bcd805
--- /dev/null
+++ b/frontend/delta/js/MochiKit/Visual.js
@@ -0,0 +1,1999 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/***
+
+MochiKit.Visual 1.5
+
+See for documentation, downloads, license, etc.
+
+(c) 2005 Bob Ippolito and others. All rights Reserved.
+
+***/
+
+MochiKit.Base.module(MochiKit, 'Visual', '1.5', ['Base', 'DOM', 'Style', 'Color', 'Position']);
+
+MochiKit.Visual._RoundCorners = function (e, options) {
+ e = MochiKit.DOM.getElement(e);
+ this._setOptions(options);
+ if (this.options.__unstable__wrapElement) {
+ e = this._doWrap(e);
+ }
+
+ var color = this.options.color;
+ var C = MochiKit.Color.Color;
+ if (this.options.color === "fromElement") {
+ color = C.fromBackground(e);
+ } else if (!(color instanceof C)) {
+ color = C.fromString(color);
+ }
+ this.isTransparent = (color.asRGB().a <= 0);
+
+ var bgColor = this.options.bgColor;
+ if (this.options.bgColor === "fromParent") {
+ bgColor = C.fromBackground(e.offsetParent);
+ } else if (!(bgColor instanceof C)) {
+ bgColor = C.fromString(bgColor);
+ }
+
+ this._roundCornersImpl(e, color, bgColor);
+};
+
+MochiKit.Visual._RoundCorners.prototype = {
+ _doWrap: function (e) {
+ var parent = e.parentNode;
+ var doc = MochiKit.DOM.currentDocument();
+ if (typeof(doc.defaultView) === "undefined"
+ || doc.defaultView === null) {
+ return e;
+ }
+ var style = doc.defaultView.getComputedStyle(e, null);
+ if (typeof(style) === "undefined" || style === null) {
+ return e;
+ }
+ var wrapper = MochiKit.DOM.DIV({"style": {
+ display: "block",
+ // convert padding to margin
+ marginTop: style.getPropertyValue("padding-top"),
+ marginRight: style.getPropertyValue("padding-right"),
+ marginBottom: style.getPropertyValue("padding-bottom"),
+ marginLeft: style.getPropertyValue("padding-left"),
+ // remove padding so the rounding looks right
+ padding: "0px"
+ /*
+ paddingRight: "0px",
+ paddingLeft: "0px"
+ */
+ }});
+ wrapper.innerHTML = e.innerHTML;
+ e.innerHTML = "";
+ e.appendChild(wrapper);
+ return e;
+ },
+
+ _roundCornersImpl: function (e, color, bgColor) {
+ if (this.options.border) {
+ this._renderBorder(e, bgColor);
+ }
+ if (this._isTopRounded()) {
+ this._roundTopCorners(e, color, bgColor);
+ }
+ if (this._isBottomRounded()) {
+ this._roundBottomCorners(e, color, bgColor);
+ }
+ },
+
+ _renderBorder: function (el, bgColor) {
+ var borderValue = "1px solid " + this._borderColor(bgColor);
+ var borderL = "border-left: " + borderValue;
+ var borderR = "border-right: " + borderValue;
+ var style = "style='" + borderL + ";" + borderR + "'";
+ el.innerHTML = "
" + el.innerHTML + "
";
+ },
+
+ _roundTopCorners: function (el, color, bgColor) {
+ var corner = this._createCorner(bgColor);
+ for (var i = 0; i < this.options.numSlices; i++) {
+ corner.appendChild(
+ this._createCornerSlice(color, bgColor, i, "top")
+ );
+ }
+ el.style.paddingTop = 0;
+ el.insertBefore(corner, el.firstChild);
+ },
+
+ _roundBottomCorners: function (el, color, bgColor) {
+ var corner = this._createCorner(bgColor);
+ for (var i = (this.options.numSlices - 1); i >= 0; i--) {
+ corner.appendChild(
+ this._createCornerSlice(color, bgColor, i, "bottom")
+ );
+ }
+ el.style.paddingBottom = 0;
+ el.appendChild(corner);
+ },
+
+ _createCorner: function (bgColor) {
+ var dom = MochiKit.DOM;
+ return dom.DIV({style: {backgroundColor: bgColor.toString()}});
+ },
+
+ _createCornerSlice: function (color, bgColor, n, position) {
+ var slice = MochiKit.DOM.SPAN();
+
+ var inStyle = slice.style;
+ inStyle.backgroundColor = color.toString();
+ inStyle.display = "block";
+ inStyle.height = "1px";
+ inStyle.overflow = "hidden";
+ inStyle.fontSize = "1px";
+
+ var borderColor = this._borderColor(color, bgColor);
+ if (this.options.border && n === 0) {
+ inStyle.borderTopStyle = "solid";
+ inStyle.borderTopWidth = "1px";
+ inStyle.borderLeftWidth = "0px";
+ inStyle.borderRightWidth = "0px";
+ inStyle.borderBottomWidth = "0px";
+ // assumes css compliant box model
+ inStyle.height = "0px";
+ inStyle.borderColor = borderColor.toString();
+ } else if (borderColor) {
+ inStyle.borderColor = borderColor.toString();
+ inStyle.borderStyle = "solid";
+ inStyle.borderWidth = "0px 1px";
+ }
+
+ if (!this.options.compact && (n == (this.options.numSlices - 1))) {
+ inStyle.height = "2px";
+ }
+
+ this._setMargin(slice, n, position);
+ this._setBorder(slice, n, position);
+
+ return slice;
+ },
+
+ _setOptions: function (options) {
+ this.options = {
+ corners: "all",
+ color: "fromElement",
+ bgColor: "fromParent",
+ blend: true,
+ border: false,
+ compact: false,
+ __unstable__wrapElement: false
+ };
+ MochiKit.Base.update(this.options, options);
+
+ this.options.numSlices = (this.options.compact ? 2 : 4);
+ },
+
+ _whichSideTop: function () {
+ var corners = this.options.corners;
+ if (this._hasString(corners, "all", "top")) {
+ return "";
+ }
+
+ var has_tl = (corners.indexOf("tl") != -1);
+ var has_tr = (corners.indexOf("tr") != -1);
+ if (has_tl && has_tr) {
+ return "";
+ }
+ if (has_tl) {
+ return "left";
+ }
+ if (has_tr) {
+ return "right";
+ }
+ return "";
+ },
+
+ _whichSideBottom: function () {
+ var corners = this.options.corners;
+ if (this._hasString(corners, "all", "bottom")) {
+ return "";
+ }
+
+ var has_bl = (corners.indexOf('bl') != -1);
+ var has_br = (corners.indexOf('br') != -1);
+ if (has_bl && has_br) {
+ return "";
+ }
+ if (has_bl) {
+ return "left";
+ }
+ if (has_br) {
+ return "right";
+ }
+ return "";
+ },
+
+ _borderColor: function (color, bgColor) {
+ if (color == "transparent") {
+ return bgColor;
+ } else if (this.options.border) {
+ return this.options.border;
+ } else if (this.options.blend) {
+ return bgColor.blendedColor(color);
+ }
+ return "";
+ },
+
+
+ _setMargin: function (el, n, corners) {
+ var marginSize = this._marginSize(n) + "px";
+ var whichSide = (
+ corners == "top" ? this._whichSideTop() : this._whichSideBottom()
+ );
+ var style = el.style;
+
+ if (whichSide == "left") {
+ style.marginLeft = marginSize;
+ style.marginRight = "0px";
+ } else if (whichSide == "right") {
+ style.marginRight = marginSize;
+ style.marginLeft = "0px";
+ } else {
+ style.marginLeft = marginSize;
+ style.marginRight = marginSize;
+ }
+ },
+
+ _setBorder: function (el, n, corners) {
+ var borderSize = this._borderSize(n) + "px";
+ var whichSide = (
+ corners == "top" ? this._whichSideTop() : this._whichSideBottom()
+ );
+
+ var style = el.style;
+ if (whichSide == "left") {
+ style.borderLeftWidth = borderSize;
+ style.borderRightWidth = "0px";
+ } else if (whichSide == "right") {
+ style.borderRightWidth = borderSize;
+ style.borderLeftWidth = "0px";
+ } else {
+ style.borderLeftWidth = borderSize;
+ style.borderRightWidth = borderSize;
+ }
+ },
+
+ _marginSize: function (n) {
+ if (this.isTransparent) {
+ return 0;
+ }
+
+ var o = this.options;
+ if (o.compact && o.blend) {
+ var smBlendedMarginSizes = [1, 0];
+ return smBlendedMarginSizes[n];
+ } else if (o.compact) {
+ var compactMarginSizes = [2, 1];
+ return compactMarginSizes[n];
+ } else if (o.blend) {
+ var blendedMarginSizes = [3, 2, 1, 0];
+ return blendedMarginSizes[n];
+ } else {
+ var marginSizes = [5, 3, 2, 1];
+ return marginSizes[n];
+ }
+ },
+
+ _borderSize: function (n) {
+ var o = this.options;
+ var borderSizes;
+ if (o.compact && (o.blend || this.isTransparent)) {
+ return 1;
+ } else if (o.compact) {
+ borderSizes = [1, 0];
+ } else if (o.blend) {
+ borderSizes = [2, 1, 1, 1];
+ } else if (o.border) {
+ borderSizes = [0, 2, 0, 0];
+ } else if (this.isTransparent) {
+ borderSizes = [5, 3, 2, 1];
+ } else {
+ return 0;
+ }
+ return borderSizes[n];
+ },
+
+ _hasString: function (str) {
+ for (var i = 1; i< arguments.length; i++) {
+ if (str.indexOf(arguments[i]) != -1) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ _isTopRounded: function () {
+ return this._hasString(this.options.corners,
+ "all", "top", "tl", "tr"
+ );
+ },
+
+ _isBottomRounded: function () {
+ return this._hasString(this.options.corners,
+ "all", "bottom", "bl", "br"
+ );
+ },
+
+ _hasSingleTextChild: function (el) {
+ return (el.childNodes.length == 1 && el.childNodes[0].nodeType == 3);
+ }
+};
+
+/** @id MochiKit.Visual.roundElement */
+MochiKit.Visual.roundElement = function (e, options) {
+ new MochiKit.Visual._RoundCorners(e, options);
+};
+
+/** @id MochiKit.Visual.roundClass */
+MochiKit.Visual.roundClass = function (tagName, className, options) {
+ var elements = MochiKit.DOM.getElementsByTagAndClassName(
+ tagName, className
+ );
+ for (var i = 0; i < elements.length; i++) {
+ MochiKit.Visual.roundElement(elements[i], options);
+ }
+};
+
+/** @id MochiKit.Visual.tagifyText */
+MochiKit.Visual.tagifyText = function (element, /* optional */tagifyStyle) {
+ /***
+
+ Change a node text to character in tags.
+
+ @param tagifyStyle: the style to apply to character nodes, default to
+ 'position: relative'.
+
+ ***/
+ tagifyStyle = tagifyStyle || 'position:relative';
+ if (/MSIE/.test(navigator.userAgent)) {
+ tagifyStyle += ';zoom:1';
+ }
+ element = MochiKit.DOM.getElement(element);
+ var ma = MochiKit.Base.map;
+ ma(function (child) {
+ if (child.nodeType == 3) {
+ ma(function (character) {
+ element.insertBefore(
+ MochiKit.DOM.SPAN({style: tagifyStyle},
+ character == ' ' ? String.fromCharCode(160) : character), child);
+ }, child.nodeValue.split(''));
+ MochiKit.DOM.removeElement(child);
+ }
+ }, element.childNodes);
+};
+
+MochiKit.Visual._forceRerendering = function (element) {
+ try {
+ element = MochiKit.DOM.getElement(element);
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch(e) {
+ }
+};
+
+/** @id MochiKit.Visual.multiple */
+MochiKit.Visual.multiple = function (elements, effect, /* optional */options) {
+ /***
+
+ Launch the same effect subsequently on given elements.
+
+ ***/
+ options = MochiKit.Base.update({
+ speed: 0.1, delay: 0.0
+ }, options);
+ var masterDelay = options.delay;
+ var index = 0;
+ MochiKit.Base.map(function (innerelement) {
+ options.delay = index * options.speed + masterDelay;
+ new effect(innerelement, options);
+ index += 1;
+ }, elements);
+};
+
+MochiKit.Visual.PAIRS = {
+ 'slide': ['slideDown', 'slideUp'],
+ 'blind': ['blindDown', 'blindUp'],
+ 'appear': ['appear', 'fade'],
+ 'size': ['grow', 'shrink']
+};
+
+/** @id MochiKit.Visual.toggle */
+MochiKit.Visual.toggle = function (element, /* optional */effect, /* optional */options) {
+ /***
+
+ Toggle an item between two state depending of its visibility, making
+ a effect between these states. Default effect is 'appear', can be
+ 'slide' or 'blind'.
+
+ ***/
+ element = MochiKit.DOM.getElement(element);
+ effect = (effect || 'appear').toLowerCase();
+ options = MochiKit.Base.update({
+ queue: {position: 'end', scope: (element.id || 'global'), limit: 1}
+ }, options);
+ var v = MochiKit.Visual;
+ v[MochiKit.Style.getStyle(element, 'display') != 'none' ?
+ v.PAIRS[effect][1] : v.PAIRS[effect][0]](element, options);
+};
+
+/***
+
+Transitions: define functions calculating variations depending of a position.
+
+***/
+
+MochiKit.Visual.Transitions = { __export__: false };
+
+/** @id MochiKit.Visual.Transitions.linear */
+MochiKit.Visual.Transitions.linear = function (pos) {
+ return pos;
+};
+
+/** @id MochiKit.Visual.Transitions.sinoidal */
+MochiKit.Visual.Transitions.sinoidal = function (pos) {
+ return 0.5 - Math.cos(pos*Math.PI)/2;
+};
+
+/** @id MochiKit.Visual.Transitions.reverse */
+MochiKit.Visual.Transitions.reverse = function (pos) {
+ return 1 - pos;
+};
+
+/** @id MochiKit.Visual.Transitions.flicker */
+MochiKit.Visual.Transitions.flicker = function (pos) {
+ return 0.25 - Math.cos(pos*Math.PI)/4 + Math.random()/2;
+};
+
+/** @id MochiKit.Visual.Transitions.wobble */
+MochiKit.Visual.Transitions.wobble = function (pos) {
+ return 0.5 - Math.cos(9*pos*Math.PI)/2;
+};
+
+/** @id MochiKit.Visual.Transitions.pulse */
+MochiKit.Visual.Transitions.pulse = function (pos, pulses) {
+ if (pulses) {
+ pos *= 2 * pulses;
+ } else {
+ pos *= 10;
+ }
+ var decimals = pos - Math.floor(pos);
+ return (Math.floor(pos) % 2 == 0) ? decimals : 1 - decimals;
+};
+
+/** @id MochiKit.Visual.Transitions.parabolic */
+MochiKit.Visual.Transitions.parabolic = function (pos) {
+ return pos * pos;
+};
+
+/** @id MochiKit.Visual.Transitions.spring */
+MochiKit.Visual.Transitions.spring = function (pos) {
+ return 1 - (Math.cos(pos * 2.5 * Math.PI) * Math.exp(-pos * 6));
+};
+
+/** @id MochiKit.Visual.Transitions.none */
+MochiKit.Visual.Transitions.none = function (pos) {
+ return 0;
+};
+
+/** @id MochiKit.Visual.Transitions.full */
+MochiKit.Visual.Transitions.full = function (pos) {
+ return 1;
+};
+
+/***
+
+Core effects
+
+***/
+
+MochiKit.Visual.ScopedQueue = function () {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls();
+ }
+ this.__init__();
+};
+MochiKit.Visual.ScopedQueue.__export__ = false;
+
+MochiKit.Base.update(MochiKit.Visual.ScopedQueue.prototype, {
+ __init__: function () {
+ this.effects = [];
+ this.interval = null;
+ },
+
+ /** @id MochiKit.Visual.ScopedQueue.prototype.add */
+ add: function (effect) {
+ var timestamp = new Date().getTime();
+
+ var position = (typeof(effect.options.queue) == 'string') ?
+ effect.options.queue : effect.options.queue.position;
+
+ var ma = MochiKit.Base.map;
+ switch (position) {
+ case 'front':
+ // move unstarted effects after this effect
+ ma(function (e) {
+ if (e.state == 'idle') {
+ e.startOn += effect.finishOn;
+ e.finishOn += effect.finishOn;
+ }
+ }, this.effects);
+ break;
+ case 'end':
+ var finish;
+ // start effect after last queued effect has finished
+ ma(function (e) {
+ var i = e.finishOn;
+ if (i >= (finish || i)) {
+ finish = i;
+ }
+ }, this.effects);
+ timestamp = finish || timestamp;
+ break;
+ case 'break':
+ ma(function (e) {
+ e.finalize();
+ }, this.effects);
+ break;
+ case 'replace':
+ ma(function (e) {
+ e.cancel();
+ }, this.effects);
+ break;
+ }
+
+ effect.startOn += timestamp;
+ effect.finishOn += timestamp;
+ if (!effect.options.queue.limit ||
+ this.effects.length < effect.options.queue.limit) {
+ this.effects.push(effect);
+ }
+
+ if (!this.interval) {
+ this.interval = this.startLoop(MochiKit.Base.bind(this.loop, this),
+ 40);
+ }
+ },
+
+ /** @id MochiKit.Visual.ScopedQueue.prototype.startLoop */
+ startLoop: function (func, interval) {
+ return setInterval(func, interval);
+ },
+
+ /** @id MochiKit.Visual.ScopedQueue.prototype.remove */
+ remove: function (effect) {
+ this.effects = MochiKit.Base.filter(function (e) {
+ return e != effect;
+ }, this.effects);
+ if (!this.effects.length) {
+ this.stopLoop(this.interval);
+ this.interval = null;
+ }
+ },
+
+ /** @id MochiKit.Visual.ScopedQueue.prototype.stopLoop */
+ stopLoop: function (interval) {
+ clearInterval(interval);
+ },
+
+ /** @id MochiKit.Visual.ScopedQueue.prototype.loop */
+ loop: function () {
+ var timePos = new Date().getTime();
+ MochiKit.Base.map(function (effect) {
+ effect.loop(timePos);
+ }, this.effects);
+ }
+});
+
+MochiKit.Visual.Queues = {
+ __export__: false,
+ instances: {},
+ get: function (queueName) {
+ if (typeof(queueName) != 'string') {
+ return queueName;
+ }
+
+ if (!this.instances[queueName]) {
+ this.instances[queueName] = new MochiKit.Visual.ScopedQueue();
+ }
+ return this.instances[queueName];
+ }
+};
+
+MochiKit.Visual.Queue = MochiKit.Visual.Queues.get('global');
+MochiKit.Visual.Queue.__export__ = false;
+
+MochiKit.Visual.DefaultOptions = {
+ __export__: false,
+ transition: MochiKit.Visual.Transitions.sinoidal,
+ duration: 1.0, // seconds
+ fps: 25.0, // max. 25fps due to MochiKit.Visual.Queue implementation
+ sync: false, // true for combining
+ from: 0.0,
+ to: 1.0,
+ delay: 0.0,
+ queue: 'parallel'
+};
+
+MochiKit.Visual.Base = function () {};
+
+MochiKit.Visual.Base.prototype = {
+ /***
+
+ Basic class for all Effects. Define a looping mechanism called for each step
+ of an effect. Don't instantiate it, only subclass it.
+
+ ***/
+
+ __class__ : MochiKit.Visual.Base,
+
+ /** @id MochiKit.Visual.Base.prototype.start */
+ start: function (options) {
+ var v = MochiKit.Visual;
+ this.options = MochiKit.Base.setdefault(options,
+ v.DefaultOptions);
+ this.currentFrame = 0;
+ this.state = 'idle';
+ this.startOn = this.options.delay*1000;
+ this.finishOn = this.startOn + (this.options.duration*1000);
+ this.event('beforeStart');
+ if (!this.options.sync) {
+ v.Queues.get(typeof(this.options.queue) == 'string' ?
+ 'global' : this.options.queue.scope).add(this);
+ }
+ },
+
+ /** @id MochiKit.Visual.Base.prototype.loop */
+ loop: function (timePos) {
+ if (timePos >= this.startOn) {
+ if (timePos >= this.finishOn) {
+ return this.finalize();
+ }
+ var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
+ var frame =
+ Math.round(pos * this.options.fps * this.options.duration);
+ if (frame > this.currentFrame) {
+ this.render(pos);
+ this.currentFrame = frame;
+ }
+ }
+ },
+
+ /** @id MochiKit.Visual.Base.prototype.render */
+ render: function (pos) {
+ if (this.state == 'idle') {
+ this.state = 'running';
+ this.event('beforeSetup');
+ this.setup();
+ this.event('afterSetup');
+ }
+ if (this.state == 'running') {
+ var trans = this.options.transition;
+ if (typeof(trans) == "string") {
+ trans = MochiKit.Visual.Transitions[trans];
+ }
+ if (typeof(trans) == "function") {
+ pos = trans(pos);
+ }
+ pos *= (this.options.to - this.options.from);
+ pos += this.options.from;
+ this.event('beforeUpdate');
+ this.update(pos);
+ this.event('afterUpdate');
+ }
+ },
+
+ /** @id MochiKit.Visual.Base.prototype.cancel */
+ cancel: function () {
+ if (!this.options.sync) {
+ MochiKit.Visual.Queues.get(typeof(this.options.queue) == 'string' ?
+ 'global' : this.options.queue.scope).remove(this);
+ }
+ this.state = 'finished';
+ },
+
+ /** @id MochiKit.Visual.Base.prototype.finalize */
+ finalize: function () {
+ this.render(1.0);
+ this.cancel();
+ this.event('beforeFinish');
+ this.finish();
+ this.event('afterFinish');
+ },
+
+ setup: function () {
+ },
+
+ finish: function () {
+ },
+
+ update: function (position) {
+ },
+
+ /** @id MochiKit.Visual.Base.prototype.event */
+ event: function (eventName) {
+ if (this.options[eventName + 'Internal']) {
+ this.options[eventName + 'Internal'](this);
+ }
+ if (this.options[eventName]) {
+ this.options[eventName](this);
+ }
+ },
+
+ /** @id MochiKit.Visual.Base.prototype.repr */
+ repr: function () {
+ return '[' + this.__class__.NAME + ', options:' +
+ MochiKit.Base.repr(this.options) + ']';
+ }
+};
+
+/** @id MochiKit.Visual.Parallel */
+MochiKit.Visual.Parallel = function (effects, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(effects, options);
+ }
+
+ this.__init__(effects, options);
+};
+
+MochiKit.Visual.Parallel.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.Parallel.prototype, {
+ /***
+
+ Run multiple effects at the same time.
+
+ ***/
+
+ __class__ : MochiKit.Visual.Parallel,
+
+ __init__: function (effects, options) {
+ this.effects = effects || [];
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.Parallel.prototype.update */
+ update: function (position) {
+ MochiKit.Base.map(function (effect) {
+ effect.render(position);
+ }, this.effects);
+ },
+
+ /** @id MochiKit.Visual.Parallel.prototype.finish */
+ finish: function () {
+ MochiKit.Base.map(function (effect) {
+ effect.finalize();
+ }, this.effects);
+ }
+});
+
+/** @id MochiKit.Visual.Sequence */
+MochiKit.Visual.Sequence = function (effects, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(effects, options);
+ }
+ this.__init__(effects, options);
+};
+
+MochiKit.Visual.Sequence.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.Sequence.prototype, {
+
+ __class__ : MochiKit.Visual.Sequence,
+
+ __init__: function (effects, options) {
+ var defs = { transition: MochiKit.Visual.Transitions.linear,
+ duration: 0 };
+ this.effects = effects || [];
+ MochiKit.Base.map(function (effect) {
+ defs.duration += effect.options.duration;
+ }, this.effects);
+ MochiKit.Base.setdefault(options, defs);
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.Sequence.prototype.update */
+ update: function (position) {
+ var time = position * this.options.duration;
+ for (var i = 0; i < this.effects.length; i++) {
+ var effect = this.effects[i];
+ if (time <= effect.options.duration) {
+ effect.render(time / effect.options.duration);
+ break;
+ } else {
+ time -= effect.options.duration;
+ }
+ }
+ },
+
+ /** @id MochiKit.Visual.Sequence.prototype.finish */
+ finish: function () {
+ MochiKit.Base.map(function (effect) {
+ effect.finalize();
+ }, this.effects);
+ }
+});
+
+/** @id MochiKit.Visual.Opacity */
+MochiKit.Visual.Opacity = function (element, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, options);
+ }
+ this.__init__(element, options);
+};
+
+MochiKit.Visual.Opacity.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.Opacity.prototype, {
+ /***
+
+ Change the opacity of an element.
+
+ @param options: 'from' and 'to' change the starting and ending opacities.
+ Must be between 0.0 and 1.0. Default to current opacity and 1.0.
+
+ ***/
+
+ __class__ : MochiKit.Visual.Opacity,
+
+ __init__: function (element, /* optional */options) {
+ var b = MochiKit.Base;
+ var s = MochiKit.Style;
+ this.element = MochiKit.DOM.getElement(element);
+ // make this work on IE on elements without 'layout'
+ if (this.element.currentStyle &&
+ (!this.element.currentStyle.hasLayout)) {
+ s.setStyle(this.element, {zoom: 1});
+ }
+ options = b.update({
+ from: s.getStyle(this.element, 'opacity') || 0.0,
+ to: 1.0
+ }, options);
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.Opacity.prototype.update */
+ update: function (position) {
+ MochiKit.Style.setStyle(this.element, {'opacity': position});
+ }
+});
+
+/** @id MochiKit.Visual.Move.prototype */
+MochiKit.Visual.Move = function (element, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, options);
+ }
+ this.__init__(element, options);
+};
+
+MochiKit.Visual.Move.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.Move.prototype, {
+ /***
+
+ Move an element between its current position to a defined position
+
+ @param options: 'x' and 'y' for final positions, default to 0, 0.
+
+ ***/
+
+ __class__ : MochiKit.Visual.Move,
+
+ __init__: function (element, /* optional */options) {
+ this.element = MochiKit.DOM.getElement(element);
+ options = MochiKit.Base.update({
+ x: 0,
+ y: 0,
+ mode: 'relative'
+ }, options);
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.Move.prototype.setup */
+ setup: function () {
+ // Bug in Opera: Opera returns the 'real' position of a static element
+ // or relative element that does not have top/left explicitly set.
+ // ==> Always set top and left for position relative elements in your
+ // stylesheets (to 0 if you do not need them)
+ MochiKit.Style.makePositioned(this.element);
+
+ var s = this.element.style;
+ var originalVisibility = s.visibility;
+ var originalDisplay = s.display;
+ if (originalDisplay == 'none') {
+ s.visibility = 'hidden';
+ s.display = '';
+ }
+
+ this.originalLeft = parseFloat(MochiKit.Style.getStyle(this.element, 'left') || '0');
+ this.originalTop = parseFloat(MochiKit.Style.getStyle(this.element, 'top') || '0');
+
+ if (this.options.mode == 'absolute') {
+ // absolute movement, so we need to calc deltaX and deltaY
+ this.options.x -= this.originalLeft;
+ this.options.y -= this.originalTop;
+ }
+ if (originalDisplay == 'none') {
+ s.visibility = originalVisibility;
+ s.display = originalDisplay;
+ }
+ },
+
+ /** @id MochiKit.Visual.Move.prototype.update */
+ update: function (position) {
+ MochiKit.Style.setStyle(this.element, {
+ left: Math.round(this.options.x * position + this.originalLeft) + 'px',
+ top: Math.round(this.options.y * position + this.originalTop) + 'px'
+ });
+ }
+});
+
+/** @id MochiKit.Visual.Scale */
+MochiKit.Visual.Scale = function (element, percent, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, percent, options);
+ }
+ this.__init__(element, percent, options);
+};
+
+MochiKit.Visual.Scale.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.Scale.prototype, {
+ /***
+
+ Change the size of an element.
+
+ @param percent: final_size = percent*original_size
+
+ @param options: several options changing scale behaviour
+
+ ***/
+
+ __class__ : MochiKit.Visual.Scale,
+
+ __init__: function (element, percent, /* optional */options) {
+ this.element = MochiKit.DOM.getElement(element);
+ options = MochiKit.Base.update({
+ scaleX: true,
+ scaleY: true,
+ scaleContent: true,
+ scaleFromCenter: false,
+ scaleMode: 'box', // 'box' or 'contents' or {} with provided values
+ scaleFrom: 100.0,
+ scaleTo: percent
+ }, options);
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.Scale.prototype.setup */
+ setup: function () {
+ this.restoreAfterFinish = this.options.restoreAfterFinish || false;
+ this.elementPositioning = MochiKit.Style.getStyle(this.element,
+ 'position');
+
+ var ma = MochiKit.Base.map;
+ var b = MochiKit.Base.bind;
+ this.originalStyle = {};
+ ma(b(function (k) {
+ this.originalStyle[k] = this.element.style[k];
+ }, this), ['top', 'left', 'width', 'height', 'fontSize']);
+
+ this.originalTop = this.element.offsetTop;
+ this.originalLeft = this.element.offsetLeft;
+
+ var fontSize = MochiKit.Style.getStyle(this.element,
+ 'font-size') || '100%';
+ ma(b(function (fontSizeType) {
+ if (fontSize.indexOf(fontSizeType) > 0) {
+ this.fontSize = parseFloat(fontSize);
+ this.fontSizeType = fontSizeType;
+ }
+ }, this), ['em', 'px', '%']);
+
+ this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
+
+ if (/^content/.test(this.options.scaleMode)) {
+ this.dims = [this.element.scrollHeight, this.element.scrollWidth];
+ } else if (this.options.scaleMode == 'box') {
+ this.dims = [this.element.offsetHeight, this.element.offsetWidth];
+ } else {
+ this.dims = [this.options.scaleMode.originalHeight,
+ this.options.scaleMode.originalWidth];
+ }
+ },
+
+ /** @id MochiKit.Visual.Scale.prototype.update */
+ update: function (position) {
+ var currentScale = (this.options.scaleFrom/100.0) +
+ (this.factor * position);
+ if (this.options.scaleContent && this.fontSize) {
+ MochiKit.Style.setStyle(this.element, {
+ fontSize: this.fontSize * currentScale + this.fontSizeType
+ });
+ }
+ this.setDimensions(this.dims[0] * currentScale,
+ this.dims[1] * currentScale);
+ },
+
+ /** @id MochiKit.Visual.Scale.prototype.finish */
+ finish: function () {
+ if (this.restoreAfterFinish) {
+ MochiKit.Style.setStyle(this.element, this.originalStyle);
+ }
+ },
+
+ /** @id MochiKit.Visual.Scale.prototype.setDimensions */
+ setDimensions: function (height, width) {
+ var d = {};
+ var r = Math.round;
+ if (/MSIE/.test(navigator.userAgent)) {
+ r = Math.ceil;
+ }
+ if (this.options.scaleX) {
+ d.width = r(width) + 'px';
+ }
+ if (this.options.scaleY) {
+ d.height = r(height) + 'px';
+ }
+ if (this.options.scaleFromCenter) {
+ var topd = (height - this.dims[0])/2;
+ var leftd = (width - this.dims[1])/2;
+ if (this.elementPositioning == 'absolute') {
+ if (this.options.scaleY) {
+ d.top = this.originalTop - topd + 'px';
+ }
+ if (this.options.scaleX) {
+ d.left = this.originalLeft - leftd + 'px';
+ }
+ } else {
+ if (this.options.scaleY) {
+ d.top = -topd + 'px';
+ }
+ if (this.options.scaleX) {
+ d.left = -leftd + 'px';
+ }
+ }
+ }
+ MochiKit.Style.setStyle(this.element, d);
+ }
+});
+
+/** @id MochiKit.Visual.Highlight */
+MochiKit.Visual.Highlight = function (element, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, options);
+ }
+ this.__init__(element, options);
+};
+
+MochiKit.Visual.Highlight.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.Highlight.prototype, {
+ /***
+
+ Highlight an item of the page.
+
+ @param options: 'startcolor' for choosing highlighting color, default
+ to '#ffff99'.
+
+ ***/
+
+ __class__ : MochiKit.Visual.Highlight,
+
+ __init__: function (element, /* optional */options) {
+ this.element = MochiKit.DOM.getElement(element);
+ options = MochiKit.Base.update({
+ startcolor: '#ffff99'
+ }, options);
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.Highlight.prototype.setup */
+ setup: function () {
+ var b = MochiKit.Base;
+ var s = MochiKit.Style;
+ // Prevent executing on elements not in the layout flow
+ if (s.getStyle(this.element, 'display') == 'none') {
+ this.cancel();
+ return;
+ }
+ // Disable background image during the effect
+ this.oldStyle = {
+ backgroundImage: s.getStyle(this.element, 'background-image')
+ };
+ s.setStyle(this.element, {
+ backgroundImage: 'none'
+ });
+
+ if (!this.options.endcolor) {
+ this.options.endcolor =
+ MochiKit.Color.Color.fromBackground(this.element).toHexString();
+ }
+ if (b.isUndefinedOrNull(this.options.restorecolor)) {
+ this.options.restorecolor = s.getStyle(this.element,
+ 'background-color');
+ }
+ // init color calculations
+ this._base = b.map(b.bind(function (i) {
+ return parseInt(
+ this.options.startcolor.slice(i*2 + 1, i*2 + 3), 16);
+ }, this), [0, 1, 2]);
+ this._delta = b.map(b.bind(function (i) {
+ return parseInt(this.options.endcolor.slice(i*2 + 1, i*2 + 3), 16)
+ - this._base[i];
+ }, this), [0, 1, 2]);
+ },
+
+ /** @id MochiKit.Visual.Highlight.prototype.update */
+ update: function (position) {
+ var m = '#';
+ MochiKit.Base.map(MochiKit.Base.bind(function (i) {
+ m += MochiKit.Color.toColorPart(Math.round(this._base[i] +
+ this._delta[i]*position));
+ }, this), [0, 1, 2]);
+ MochiKit.Style.setStyle(this.element, {
+ backgroundColor: m
+ });
+ },
+
+ /** @id MochiKit.Visual.Highlight.prototype.finish */
+ finish: function () {
+ MochiKit.Style.setStyle(this.element,
+ MochiKit.Base.update(this.oldStyle, {
+ backgroundColor: this.options.restorecolor
+ }));
+ }
+});
+
+/** @id MochiKit.Visual.ScrollTo */
+MochiKit.Visual.ScrollTo = function (element, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, options);
+ }
+ this.__init__(element, options);
+};
+
+MochiKit.Visual.ScrollTo.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.ScrollTo.prototype, {
+ /***
+
+ Scroll to an element in the page.
+
+ ***/
+
+ __class__ : MochiKit.Visual.ScrollTo,
+
+ __init__: function (element, /* optional */options) {
+ this.element = MochiKit.DOM.getElement(element);
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.ScrollTo.prototype.setup */
+ setup: function () {
+ var p = MochiKit.Position;
+ p.prepare();
+ var offsets = p.cumulativeOffset(this.element);
+ if (this.options.offset) {
+ offsets.y += this.options.offset;
+ }
+ var max;
+ if (window.innerHeight) {
+ max = window.innerHeight - window.height;
+ } else if (document.documentElement &&
+ document.documentElement.clientHeight) {
+ max = document.documentElement.clientHeight -
+ document.body.scrollHeight;
+ } else if (document.body) {
+ max = document.body.clientHeight - document.body.scrollHeight;
+ }
+ this.scrollStart = p.windowOffset.y;
+ this.delta = (offsets.y > max ? max : offsets.y) - this.scrollStart;
+ },
+
+ /** @id MochiKit.Visual.ScrollTo.prototype.update */
+ update: function (position) {
+ var p = MochiKit.Position;
+ p.prepare();
+ window.scrollTo(p.windowOffset.x, this.scrollStart + (position * this.delta));
+ }
+});
+
+MochiKit.Visual._CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;
+
+MochiKit.Visual.Morph = function (element, options) {
+ var cls = arguments.callee;
+ if (!(this instanceof cls)) {
+ return new cls(element, options);
+ }
+ this.__init__(element, options);
+};
+
+MochiKit.Visual.Morph.prototype = new MochiKit.Visual.Base();
+
+MochiKit.Base.update(MochiKit.Visual.Morph.prototype, {
+ /***
+
+ Morph effect: make a transformation from current style to the given style,
+ automatically making a transition between the two.
+
+ ***/
+
+ __class__ : MochiKit.Visual.Morph,
+
+ __init__: function (element, /* optional */options) {
+ this.element = MochiKit.DOM.getElement(element);
+ this.start(options);
+ },
+
+ /** @id MochiKit.Visual.Morph.prototype.setup */
+ setup: function () {
+ var b = MochiKit.Base;
+ var style = this.options.style;
+ this.styleStart = {};
+ this.styleEnd = {};
+ this.units = {};
+ var value, unit;
+ for (var s in style) {
+ value = style[s];
+ s = b.camelize(s);
+ if (MochiKit.Visual._CSS_LENGTH.test(value)) {
+ var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+ value = parseFloat(components[1]);
+ unit = (components.length == 3) ? components[2] : null;
+ this.styleEnd[s] = value;
+ this.units[s] = unit;
+ value = MochiKit.Style.getStyle(this.element, s);
+ components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/);
+ value = parseFloat(components[1]);
+ this.styleStart[s] = value;
+ } else if (/[Cc]olor$/.test(s)) {
+ var c = MochiKit.Color.Color;
+ value = c.fromString(value);
+ if (value) {
+ this.units[s] = "color";
+ this.styleEnd[s] = value.toHexString();
+ value = MochiKit.Style.getStyle(this.element, s);
+ this.styleStart[s] = c.fromString(value).toHexString();
+
+ this.styleStart[s] = b.map(b.bind(function (i) {
+ return parseInt(
+ this.styleStart[s].slice(i*2 + 1, i*2 + 3), 16);
+ }, this), [0, 1, 2]);
+ this.styleEnd[s] = b.map(b.bind(function (i) {
+ return parseInt(
+ this.styleEnd[s].slice(i*2 + 1, i*2 + 3), 16);
+ }, this), [0, 1, 2]);
+ }
+ } else {
+ // For non-length & non-color properties, we just set the value
+ this.element.style[s] = value;
+ }
+ }
+ },
+
+ /** @id MochiKit.Visual.Morph.prototype.update */
+ update: function (position) {
+ var value;
+ for (var s in this.styleStart) {
+ if (this.units[s] == "color") {
+ var m = '#';
+ var start = this.styleStart[s];
+ var end = this.styleEnd[s];
+ MochiKit.Base.map(MochiKit.Base.bind(function (i) {
+ m += MochiKit.Color.toColorPart(Math.round(start[i] +
+ (end[i] - start[i])*position));
+ }, this), [0, 1, 2]);
+ this.element.style[s] = m;
+ } else {
+ value = this.styleStart[s] + Math.round((this.styleEnd[s] - this.styleStart[s]) * position * 1000) / 1000 + this.units[s];
+ this.element.style[s] = value;
+ }
+ }
+ }
+});
+
+/***
+
+Combination effects.
+
+***/
+
+/** @id MochiKit.Visual.fade */
+MochiKit.Visual.fade = function (element, /* optional */ options) {
+ /***
+
+ Fade a given element: change its opacity and hide it in the end.
+
+ @param options: 'to' and 'from' to change opacity.
+
+ ***/
+ var s = MochiKit.Style;
+ var oldOpacity = s.getStyle(element, 'opacity');
+ options = MochiKit.Base.update({
+ from: s.getStyle(element, 'opacity') || 1.0,
+ to: 0.0,
+ afterFinishInternal: function (effect) {
+ if (effect.options.to !== 0) {
+ return;
+ }
+ s.hideElement(effect.element);
+ s.setStyle(effect.element, {'opacity': oldOpacity});
+ }
+ }, options);
+ return new MochiKit.Visual.Opacity(element, options);
+};
+
+/** @id MochiKit.Visual.appear */
+MochiKit.Visual.appear = function (element, /* optional */ options) {
+ /***
+
+ Make an element appear.
+
+ @param options: 'to' and 'from' to change opacity.
+
+ ***/
+ var s = MochiKit.Style;
+ var v = MochiKit.Visual;
+ options = MochiKit.Base.update({
+ from: (s.getStyle(element, 'display') == 'none' ? 0.0 :
+ s.getStyle(element, 'opacity') || 0.0),
+ to: 1.0,
+ // force Safari to render floated elements properly
+ afterFinishInternal: function (effect) {
+ v._forceRerendering(effect.element);
+ },
+ beforeSetupInternal: function (effect) {
+ s.setStyle(effect.element, {'opacity': effect.options.from});
+ s.showElement(effect.element);
+ }
+ }, options);
+ return new v.Opacity(element, options);
+};
+
+/** @id MochiKit.Visual.puff */
+MochiKit.Visual.puff = function (element, /* optional */ options) {
+ /***
+
+ 'Puff' an element: grow it to double size, fading it and make it hidden.
+
+ ***/
+ var s = MochiKit.Style;
+ var v = MochiKit.Visual;
+ element = MochiKit.DOM.getElement(element);
+ var elementDimensions = MochiKit.Style.getElementDimensions(element, true);
+ var oldStyle = {
+ position: s.getStyle(element, 'position'),
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height,
+ opacity: s.getStyle(element, 'opacity')
+ };
+ options = MochiKit.Base.update({
+ beforeSetupInternal: function (effect) {
+ MochiKit.Position.absolutize(effect.effects[0].element);
+ },
+ afterFinishInternal: function (effect) {
+ s.hideElement(effect.effects[0].element);
+ s.setStyle(effect.effects[0].element, oldStyle);
+ },
+ scaleContent: true,
+ scaleFromCenter: true
+ }, options);
+ return new v.Parallel(
+ [new v.Scale(element, 200,
+ {sync: true, scaleFromCenter: options.scaleFromCenter,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ scaleContent: options.scaleContent, restoreAfterFinish: true}),
+ new v.Opacity(element, {sync: true, to: 0.0 })],
+ options);
+};
+
+/** @id MochiKit.Visual.blindUp */
+MochiKit.Visual.blindUp = function (element, /* optional */ options) {
+ /***
+
+ Blind an element up: change its vertical size to 0.
+
+ ***/
+ var d = MochiKit.DOM;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ var elementDimensions = s.getElementDimensions(element, true);
+ var elemClip = s.makeClipping(element);
+ options = MochiKit.Base.update({
+ scaleContent: false,
+ scaleX: false,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ restoreAfterFinish: true,
+ afterFinishInternal: function (effect) {
+ s.hideElement(effect.element);
+ s.undoClipping(effect.element, elemClip);
+ }
+ }, options);
+ return new MochiKit.Visual.Scale(element, 0, options);
+};
+
+/** @id MochiKit.Visual.blindDown */
+MochiKit.Visual.blindDown = function (element, /* optional */ options) {
+ /***
+
+ Blind an element down: restore its vertical size.
+
+ ***/
+ var d = MochiKit.DOM;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ var elementDimensions = s.getElementDimensions(element, true);
+ var elemClip;
+ options = MochiKit.Base.update({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ restoreAfterFinish: true,
+ afterSetupInternal: function (effect) {
+ elemClip = s.makeClipping(effect.element);
+ s.setStyle(effect.element, {height: '0px'});
+ s.showElement(effect.element);
+ },
+ afterFinishInternal: function (effect) {
+ s.undoClipping(effect.element, elemClip);
+ }
+ }, options);
+ return new MochiKit.Visual.Scale(element, 100, options);
+};
+
+/** @id MochiKit.Visual.switchOff */
+MochiKit.Visual.switchOff = function (element, /* optional */ options) {
+ /***
+
+ Apply a switch-off-like effect.
+
+ ***/
+ var d = MochiKit.DOM;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ var elementDimensions = s.getElementDimensions(element, true);
+ var oldOpacity = s.getStyle(element, 'opacity');
+ var elemClip;
+ options = MochiKit.Base.update({
+ duration: 0.7,
+ restoreAfterFinish: true,
+ beforeSetupInternal: function (effect) {
+ s.makePositioned(element);
+ elemClip = s.makeClipping(element);
+ },
+ afterFinishInternal: function (effect) {
+ s.hideElement(element);
+ s.undoClipping(element, elemClip);
+ s.undoPositioned(element);
+ s.setStyle(element, {'opacity': oldOpacity});
+ }
+ }, options);
+ var v = MochiKit.Visual;
+ return new v.Sequence(
+ [new v.appear(element,
+ { sync: true, duration: 0.57 * options.duration,
+ from: 0, transition: v.Transitions.flicker }),
+ new v.Scale(element, 1,
+ { sync: true, duration: 0.43 * options.duration,
+ scaleFromCenter: true, scaleX: false,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ scaleContent: false, restoreAfterFinish: true })],
+ options);
+};
+
+/** @id MochiKit.Visual.dropOut */
+MochiKit.Visual.dropOut = function (element, /* optional */ options) {
+ /***
+
+ Make an element fall and disappear.
+
+ ***/
+ var d = MochiKit.DOM;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ var oldStyle = {
+ top: s.getStyle(element, 'top'),
+ left: s.getStyle(element, 'left'),
+ opacity: s.getStyle(element, 'opacity')
+ };
+
+ options = MochiKit.Base.update({
+ duration: 0.5,
+ distance: 100,
+ beforeSetupInternal: function (effect) {
+ s.makePositioned(effect.effects[0].element);
+ },
+ afterFinishInternal: function (effect) {
+ s.hideElement(effect.effects[0].element);
+ s.undoPositioned(effect.effects[0].element);
+ s.setStyle(effect.effects[0].element, oldStyle);
+ }
+ }, options);
+ var v = MochiKit.Visual;
+ return new v.Parallel(
+ [new v.Move(element, {x: 0, y: options.distance, sync: true}),
+ new v.Opacity(element, {sync: true, to: 0.0})],
+ options);
+};
+
+/** @id MochiKit.Visual.shake */
+MochiKit.Visual.shake = function (element, /* optional */ options) {
+ /***
+
+ Move an element from left to right several times.
+
+ ***/
+ var d = MochiKit.DOM;
+ var v = MochiKit.Visual;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ var oldStyle = {
+ top: s.getStyle(element, 'top'),
+ left: s.getStyle(element, 'left')
+ };
+ options = MochiKit.Base.update({
+ duration: 0.5,
+ afterFinishInternal: function (effect) {
+ s.undoPositioned(element);
+ s.setStyle(element, oldStyle);
+ }
+ }, options);
+ return new v.Sequence(
+ [new v.Move(element, { sync: true, duration: 0.1 * options.duration,
+ x: 20, y: 0 }),
+ new v.Move(element, { sync: true, duration: 0.2 * options.duration,
+ x: -40, y: 0 }),
+ new v.Move(element, { sync: true, duration: 0.2 * options.duration,
+ x: 40, y: 0 }),
+ new v.Move(element, { sync: true, duration: 0.2 * options.duration,
+ x: -40, y: 0 }),
+ new v.Move(element, { sync: true, duration: 0.2 * options.duration,
+ x: 40, y: 0 }),
+ new v.Move(element, { sync: true, duration: 0.1 * options.duration,
+ x: -20, y: 0 })],
+ options);
+};
+
+/** @id MochiKit.Visual.slideDown */
+MochiKit.Visual.slideDown = function (element, /* optional */ options) {
+ /***
+
+ Slide an element down.
+ It needs to have the content of the element wrapped in a container
+ element with fixed height.
+
+ ***/
+ var d = MochiKit.DOM;
+ var b = MochiKit.Base;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ if (!element.firstChild) {
+ throw new Error("MochiKit.Visual.slideDown must be used on a element with a child");
+ }
+ d.removeEmptyTextNodes(element);
+ var oldInnerBottom = s.getStyle(element.firstChild, 'bottom') || 0;
+ var elementDimensions = s.getElementDimensions(element, true);
+ var elemClip;
+ options = b.update({
+ scaleContent: false,
+ scaleX: false,
+ scaleFrom: 0,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ restoreAfterFinish: true,
+ afterSetupInternal: function (effect) {
+ s.makePositioned(effect.element);
+ s.makePositioned(effect.element.firstChild);
+ if (/Opera/.test(navigator.userAgent)) {
+ s.setStyle(effect.element, {top: ''});
+ }
+ elemClip = s.makeClipping(effect.element);
+ s.setStyle(effect.element, {height: '0px'});
+ s.showElement(effect.element);
+ },
+ afterUpdateInternal: function (effect) {
+ var elementDimensions = s.getElementDimensions(effect.element, true);
+ s.setStyle(effect.element.firstChild,
+ {bottom: (effect.dims[0] - elementDimensions.h) + 'px'});
+ },
+ afterFinishInternal: function (effect) {
+ s.undoClipping(effect.element, elemClip);
+ // IE will crash if child is undoPositioned first
+ if (/MSIE/.test(navigator.userAgent)) {
+ s.undoPositioned(effect.element);
+ s.undoPositioned(effect.element.firstChild);
+ } else {
+ s.undoPositioned(effect.element.firstChild);
+ s.undoPositioned(effect.element);
+ }
+ s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom});
+ }
+ }, options);
+
+ return new MochiKit.Visual.Scale(element, 100, options);
+};
+
+/** @id MochiKit.Visual.slideUp */
+MochiKit.Visual.slideUp = function (element, /* optional */ options) {
+ /***
+
+ Slide an element up.
+ It needs to have the content of the element wrapped in a container
+ element with fixed height.
+
+ ***/
+ var d = MochiKit.DOM;
+ var b = MochiKit.Base;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ if (!element.firstChild) {
+ throw new Error("MochiKit.Visual.slideUp must be used on a element with a child");
+ }
+ d.removeEmptyTextNodes(element);
+ var oldInnerBottom = s.getStyle(element.firstChild, 'bottom');
+ var elementDimensions = s.getElementDimensions(element, true);
+ var elemClip;
+ options = b.update({
+ scaleContent: false,
+ scaleX: false,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ scaleFrom: 100,
+ restoreAfterFinish: true,
+ beforeStartInternal: function (effect) {
+ s.makePositioned(effect.element);
+ s.makePositioned(effect.element.firstChild);
+ if (/Opera/.test(navigator.userAgent)) {
+ s.setStyle(effect.element, {top: ''});
+ }
+ elemClip = s.makeClipping(effect.element);
+ s.showElement(effect.element);
+ },
+ afterUpdateInternal: function (effect) {
+ var elementDimensions = s.getElementDimensions(effect.element, true);
+ s.setStyle(effect.element.firstChild,
+ {bottom: (effect.dims[0] - elementDimensions.h) + 'px'});
+ },
+ afterFinishInternal: function (effect) {
+ s.hideElement(effect.element);
+ s.undoClipping(effect.element, elemClip);
+ s.undoPositioned(effect.element.firstChild);
+ s.undoPositioned(effect.element);
+ s.setStyle(effect.element.firstChild, {bottom: oldInnerBottom});
+ }
+ }, options);
+ return new MochiKit.Visual.Scale(element, 0, options);
+};
+
+// Bug in opera makes the TD containing this element expand for a instance
+// after finish
+/** @id MochiKit.Visual.squish */
+MochiKit.Visual.squish = function (element, /* optional */ options) {
+ /***
+
+ Reduce an element and make it disappear.
+
+ ***/
+ var d = MochiKit.DOM;
+ var b = MochiKit.Base;
+ var s = MochiKit.Style;
+ var elementDimensions = s.getElementDimensions(element, true);
+ var elemClip;
+ options = b.update({
+ restoreAfterFinish: true,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ beforeSetupInternal: function (effect) {
+ elemClip = s.makeClipping(effect.element);
+ },
+ afterFinishInternal: function (effect) {
+ s.hideElement(effect.element);
+ s.undoClipping(effect.element, elemClip);
+ }
+ }, options);
+
+ return new MochiKit.Visual.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, options);
+};
+
+/** @id MochiKit.Visual.grow */
+MochiKit.Visual.grow = function (element, /* optional */ options) {
+ /***
+
+ Grow an element to its original size. Make it zero-sized before
+ if necessary.
+
+ ***/
+ var d = MochiKit.DOM;
+ var v = MochiKit.Visual;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ options = MochiKit.Base.update({
+ direction: 'center',
+ moveTransition: v.Transitions.sinoidal,
+ scaleTransition: v.Transitions.sinoidal,
+ opacityTransition: v.Transitions.full,
+ scaleContent: true,
+ scaleFromCenter: false
+ }, options);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: s.getStyle(element, 'opacity')
+ };
+ var dims = s.getElementDimensions(element, true);
+ var initialMoveX, initialMoveY;
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ initialMoveX = initialMoveY = moveX = moveY = 0;
+ break;
+ case 'top-right':
+ initialMoveX = dims.w;
+ initialMoveY = moveY = 0;
+ moveX = -dims.w;
+ break;
+ case 'bottom-left':
+ initialMoveX = moveX = 0;
+ initialMoveY = dims.h;
+ moveY = -dims.h;
+ break;
+ case 'bottom-right':
+ initialMoveX = dims.w;
+ initialMoveY = dims.h;
+ moveX = -dims.w;
+ moveY = -dims.h;
+ break;
+ case 'center':
+ initialMoveX = dims.w / 2;
+ initialMoveY = dims.h / 2;
+ moveX = -dims.w / 2;
+ moveY = -dims.h / 2;
+ break;
+ }
+
+ var optionsParallel = MochiKit.Base.update({
+ beforeSetupInternal: function (effect) {
+ s.setStyle(effect.effects[0].element, {height: '0px'});
+ s.showElement(effect.effects[0].element);
+ },
+ afterFinishInternal: function (effect) {
+ s.undoClipping(effect.effects[0].element);
+ s.undoPositioned(effect.effects[0].element);
+ s.setStyle(effect.effects[0].element, oldStyle);
+ }
+ }, options);
+
+ return new v.Move(element, {
+ x: initialMoveX,
+ y: initialMoveY,
+ duration: 0.01,
+ beforeSetupInternal: function (effect) {
+ s.hideElement(effect.element);
+ s.makeClipping(effect.element);
+ s.makePositioned(effect.element);
+ },
+ afterFinishInternal: function (effect) {
+ new v.Parallel(
+ [new v.Opacity(effect.element, {
+ sync: true, to: 1.0, from: 0.0,
+ transition: options.opacityTransition
+ }),
+ new v.Move(effect.element, {
+ x: moveX, y: moveY, sync: true,
+ transition: options.moveTransition
+ }),
+ new v.Scale(effect.element, 100, {
+ scaleMode: {originalHeight: dims.h,
+ originalWidth: dims.w},
+ sync: true,
+ scaleFrom: /Opera/.test(navigator.userAgent) ? 1 : 0,
+ transition: options.scaleTransition,
+ scaleContent: options.scaleContent,
+ scaleFromCenter: options.scaleFromCenter,
+ restoreAfterFinish: true
+ })
+ ], optionsParallel
+ );
+ }
+ });
+};
+
+/** @id MochiKit.Visual.shrink */
+MochiKit.Visual.shrink = function (element, /* optional */ options) {
+ /***
+
+ Shrink an element and make it disappear.
+
+ ***/
+ var d = MochiKit.DOM;
+ var v = MochiKit.Visual;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ options = MochiKit.Base.update({
+ direction: 'center',
+ moveTransition: v.Transitions.sinoidal,
+ scaleTransition: v.Transitions.sinoidal,
+ opacityTransition: v.Transitions.none,
+ scaleContent: true,
+ scaleFromCenter: false
+ }, options);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ height: element.style.height,
+ width: element.style.width,
+ opacity: s.getStyle(element, 'opacity')
+ };
+
+ var dims = s.getElementDimensions(element, true);
+ var moveX, moveY;
+
+ switch (options.direction) {
+ case 'top-left':
+ moveX = moveY = 0;
+ break;
+ case 'top-right':
+ moveX = dims.w;
+ moveY = 0;
+ break;
+ case 'bottom-left':
+ moveX = 0;
+ moveY = dims.h;
+ break;
+ case 'bottom-right':
+ moveX = dims.w;
+ moveY = dims.h;
+ break;
+ case 'center':
+ moveX = dims.w / 2;
+ moveY = dims.h / 2;
+ break;
+ }
+ var elemClip;
+
+ var optionsParallel = MochiKit.Base.update({
+ beforeStartInternal: function (effect) {
+ s.makePositioned(effect.effects[0].element);
+ elemClip = s.makeClipping(effect.effects[0].element);
+ },
+ afterFinishInternal: function (effect) {
+ s.hideElement(effect.effects[0].element);
+ s.undoClipping(effect.effects[0].element, elemClip);
+ s.undoPositioned(effect.effects[0].element);
+ s.setStyle(effect.effects[0].element, oldStyle);
+ }
+ }, options);
+
+ return new v.Parallel(
+ [new v.Opacity(element, {
+ sync: true, to: 0.0, from: 1.0,
+ transition: options.opacityTransition
+ }),
+ new v.Scale(element, /Opera/.test(navigator.userAgent) ? 1 : 0, {
+ scaleMode: {originalHeight: dims.h, originalWidth: dims.w},
+ sync: true, transition: options.scaleTransition,
+ scaleContent: options.scaleContent,
+ scaleFromCenter: options.scaleFromCenter,
+ restoreAfterFinish: true
+ }),
+ new v.Move(element, {
+ x: moveX, y: moveY, sync: true, transition: options.moveTransition
+ })
+ ], optionsParallel
+ );
+};
+
+/** @id MochiKit.Visual.pulsate */
+MochiKit.Visual.pulsate = function (element, /* optional */ options) {
+ /***
+
+ Pulse an element between appear/fade.
+
+ ***/
+ var d = MochiKit.DOM;
+ var v = MochiKit.Visual;
+ var b = MochiKit.Base;
+ var oldOpacity = MochiKit.Style.getStyle(element, 'opacity');
+ options = b.update({
+ duration: 3.0,
+ from: 0,
+ afterFinishInternal: function (effect) {
+ MochiKit.Style.setStyle(effect.element, {'opacity': oldOpacity});
+ }
+ }, options);
+ var transition = options.transition || v.Transitions.sinoidal;
+ options.transition = function (pos) {
+ return transition(1 - v.Transitions.pulse(pos, options.pulses));
+ };
+ return new v.Opacity(element, options);
+};
+
+/** @id MochiKit.Visual.fold */
+MochiKit.Visual.fold = function (element, /* optional */ options) {
+ /***
+
+ Fold an element, first vertically, then horizontally.
+
+ ***/
+ var d = MochiKit.DOM;
+ var v = MochiKit.Visual;
+ var s = MochiKit.Style;
+ element = d.getElement(element);
+ var elementDimensions = s.getElementDimensions(element, true);
+ var oldStyle = {
+ top: element.style.top,
+ left: element.style.left,
+ width: element.style.width,
+ height: element.style.height
+ };
+ var elemClip = s.makeClipping(element);
+ options = MochiKit.Base.update({
+ scaleContent: false,
+ scaleX: false,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ afterFinishInternal: function (effect) {
+ new v.Scale(element, 1, {
+ scaleContent: false,
+ scaleY: false,
+ scaleMode: {originalHeight: elementDimensions.h,
+ originalWidth: elementDimensions.w},
+ afterFinishInternal: function (effect) {
+ s.hideElement(effect.element);
+ s.undoClipping(effect.element, elemClip);
+ s.setStyle(effect.element, oldStyle);
+ }
+ });
+ }
+ }, options);
+ return new v.Scale(element, 5, options);
+};
+
+
+MochiKit.Base.nameFunctions(MochiKit.Visual);
+MochiKit.Base._exportSymbols(this, MochiKit.Visual);
diff --git a/frontend/delta/js/React/react-0.4.1.js b/frontend/delta/js/React/react-0.4.1.js
new file mode 100644
index 0000000..d029de2
--- /dev/null
+++ b/frontend/delta/js/React/react-0.4.1.js
@@ -0,0 +1,11491 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+/**
+ * React v0.4.1
+ */
+(function(e){if("function"==typeof bootstrap)bootstrap("react",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeReact=e}else"undefined"!=typeof window?window.React=e():global.React=e()})(function(){var define,ses,bootstrap,module,exports;
+return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s createMarkupForStyles({width: '200px', height: 0})
+ * "width:200px;height:0;"
+ *
+ * Undefined values are ignored so that declarative programming is easier.
+ *
+ * @param {object} styles
+ * @return {?string}
+ */
+ createMarkupForStyles: function(styles) {
+ var serialized = '';
+ for (var styleName in styles) {
+ if (!styles.hasOwnProperty(styleName)) {
+ continue;
+ }
+ var styleValue = styles[styleName];
+ if (styleValue != null) {
+ serialized += processStyleName(styleName) + ':';
+ serialized += dangerousStyleValue(styleName, styleValue) + ';';
+ }
+ }
+ return serialized || null;
+ },
+
+ /**
+ * Sets the value for multiple styles on a node. If a value is specified as
+ * '' (empty string), the corresponding style property will be unset.
+ *
+ * @param {DOMElement} node
+ * @param {object} styles
+ */
+ setValueForStyles: function(node, styles) {
+ var style = node.style;
+ for (var styleName in styles) {
+ if (!styles.hasOwnProperty(styleName)) {
+ continue;
+ }
+ var styleValue = dangerousStyleValue(styleName, styles[styleName]);
+ if (styleValue) {
+ style[styleName] = styleValue;
+ } else {
+ var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
+ if (expansion) {
+ // Shorthand property that IE8 won't like unsetting, so unset each
+ // component to placate it
+ for (var individualStyleName in expansion) {
+ style[individualStyleName] = '';
+ }
+ } else {
+ style[styleName] = '';
+ }
+ }
+ }
+ }
+
+};
+
+module.exports = CSSPropertyOperations;
+
+},{"./CSSProperty":2,"./dangerousStyleValue":65,"./escapeTextForBrowser":67,"./hyphenate":76,"./memoizeStringOnly":83}],4:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule CallbackRegistry
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var listenerBank = {};
+
+/**
+ * Stores "listeners" by `registrationName`/`id`. There should be at most one
+ * "listener" per `registrationName`/`id` in the `listenerBank`.
+ *
+ * Access listeners via `listenerBank[registrationName][id]`.
+ *
+ * @class CallbackRegistry
+ * @internal
+ */
+var CallbackRegistry = {
+
+ /**
+ * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
+ *
+ * @param {string} id ID of the DOM element.
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
+ * @param {?function} listener The callback to store.
+ */
+ putListener: function(id, registrationName, listener) {
+ var bankForRegistrationName =
+ listenerBank[registrationName] || (listenerBank[registrationName] = {});
+ bankForRegistrationName[id] = listener;
+ },
+
+ /**
+ * @param {string} id ID of the DOM element.
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
+ * @return {?function} The stored callback.
+ */
+ getListener: function(id, registrationName) {
+ var bankForRegistrationName = listenerBank[registrationName];
+ return bankForRegistrationName && bankForRegistrationName[id];
+ },
+
+ /**
+ * Deletes a listener from the registration bank.
+ *
+ * @param {string} id ID of the DOM element.
+ * @param {string} registrationName Name of listener (e.g. `onClick`).
+ */
+ deleteListener: function(id, registrationName) {
+ var bankForRegistrationName = listenerBank[registrationName];
+ if (bankForRegistrationName) {
+ delete bankForRegistrationName[id];
+ }
+ },
+
+ /**
+ * Deletes all listeners for the DOM element with the supplied ID.
+ *
+ * @param {string} id ID of the DOM element.
+ */
+ deleteAllListeners: function(id) {
+ for (var registrationName in listenerBank) {
+ delete listenerBank[registrationName][id];
+ }
+ },
+
+ /**
+ * This is needed for tests only. Do not use!
+ */
+ __purge: function() {
+ listenerBank = {};
+ }
+
+};
+
+module.exports = CallbackRegistry;
+
+},{}],5:[function(require,module,exports){
+(function(){/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ChangeEventPlugin
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var SyntheticEvent = require("./SyntheticEvent");
+
+var isEventSupported = require("./isEventSupported");
+var keyOf = require("./keyOf");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+ change: {
+ phasedRegistrationNames: {
+ bubbled: keyOf({onChange: null}),
+ captured: keyOf({onChangeCapture: null})
+ }
+ }
+};
+
+/**
+ * For IE shims
+ */
+var activeElement = null;
+var activeElementID = null;
+var activeElementValue = null;
+var activeElementValueProp = null;
+
+
+/**
+ * SECTION: handle `change` event
+ */
+function shouldUseChangeEvent(elem) {
+ return (
+ elem.nodeName === 'SELECT' ||
+ (elem.nodeName === 'INPUT' && elem.type === 'file')
+ );
+}
+
+var doesChangeEventBubble = false;
+if (ExecutionEnvironment.canUseDOM) {
+ // See `handleChange` comment below
+ doesChangeEventBubble = isEventSupported('change') && (
+ !('documentMode' in document) || document.documentMode > 8
+ );
+}
+
+function manualDispatchChangeEvent(nativeEvent) {
+ var event = SyntheticEvent.getPooled(
+ eventTypes.change,
+ activeElementID,
+ nativeEvent
+ );
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+
+ // If change bubbled, we'd just bind to it like all the other events
+ // and have it go through ReactEventTopLevelCallback. Since it doesn't, we
+ // manually listen for the change event and so we have to enqueue and
+ // process the abstract event manually.
+ EventPluginHub.enqueueEvents(event);
+ EventPluginHub.processEventQueue();
+}
+
+function startWatchingForChangeEventIE8(target, targetID) {
+ activeElement = target;
+ activeElementID = targetID;
+ activeElement.attachEvent('onchange', manualDispatchChangeEvent);
+}
+
+function stopWatchingForChangeEventIE8() {
+ if (!activeElement) {
+ return;
+ }
+ activeElement.detachEvent('onchange', manualDispatchChangeEvent);
+ activeElement = null;
+ activeElementID = null;
+}
+
+function getTargetIDForChangeEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topChange) {
+ return topLevelTargetID;
+ }
+}
+function handleEventsForChangeEventIE8(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topFocus) {
+ // stopWatching() should be a noop here but we call it just in case we
+ // missed a blur event somehow.
+ stopWatchingForChangeEventIE8();
+ startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
+ } else if (topLevelType === topLevelTypes.topBlur) {
+ stopWatchingForChangeEventIE8();
+ }
+}
+
+
+/**
+ * SECTION: handle `input` event
+ */
+var isInputEventSupported = false;
+if (ExecutionEnvironment.canUseDOM) {
+ // IE9 claims to support the input event but fails to trigger it when
+ // deleting text, so we ignore its input events
+ isInputEventSupported = isEventSupported('input') && (
+ !('documentMode' in document) || document.documentMode > 9
+ );
+}
+
+
+/**
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
+ */
+var supportedInputTypes = {
+ 'color': true,
+ 'date': true,
+ 'datetime': true,
+ 'datetime-local': true,
+ 'email': true,
+ 'month': true,
+ 'number': true,
+ 'password': true,
+ 'range': true,
+ 'search': true,
+ 'tel': true,
+ 'text': true,
+ 'time': true,
+ 'url': true,
+ 'week': true
+};
+
+function shouldUseInputEvent(elem) {
+ return (
+ (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type]) ||
+ elem.nodeName === 'TEXTAREA'
+ );
+}
+
+/**
+ * (For old IE.) Replacement getter/setter for the `value` property that gets
+ * set on the active element.
+ */
+var newValueProp = {
+ get: function() {
+ return activeElementValueProp.get.call(this);
+ },
+ set: function(val) {
+ // Cast to a string so we can do equality checks.
+ activeElementValue = '' + val;
+ activeElementValueProp.set.call(this, val);
+ }
+};
+
+/**
+ * (For old IE.) Starts tracking propertychange events on the passed-in element
+ * and override the value property so that we can distinguish user events from
+ * value changes in JS.
+ */
+function startWatchingForValueChange(target, targetID) {
+ activeElement = target;
+ activeElementID = targetID;
+ activeElementValue = target.value;
+ activeElementValueProp = Object.getOwnPropertyDescriptor(
+ target.constructor.prototype,
+ 'value'
+ );
+
+ Object.defineProperty(activeElement, 'value', newValueProp);
+ activeElement.attachEvent('onpropertychange', handlePropertyChange);
+}
+
+/**
+ * (For old IE.) Removes the event listeners from the currently-tracked element,
+ * if any exists.
+ */
+function stopWatchingForValueChange() {
+ if (!activeElement) {
+ return;
+ }
+
+ // delete restores the original property definition
+ delete activeElement.value;
+ activeElement.detachEvent('onpropertychange', handlePropertyChange);
+
+ activeElement = null;
+ activeElementID = null;
+ activeElementValue = null;
+ activeElementValueProp = null;
+}
+
+/**
+ * (For old IE.) Handles a propertychange event, sending a `change` event if
+ * the value of the active element has changed.
+ */
+function handlePropertyChange(nativeEvent) {
+ if (nativeEvent.propertyName !== 'value') {
+ return;
+ }
+ var value = nativeEvent.srcElement.value;
+ if (value === activeElementValue) {
+ return;
+ }
+ activeElementValue = value;
+
+ manualDispatchChangeEvent(nativeEvent);
+}
+
+/**
+ * If a `change` event should be fired, returns the target's ID.
+ */
+function getTargetIDForInputEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topInput) {
+ // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
+ // what we want so fall through here and trigger an abstract event
+ return topLevelTargetID;
+ }
+}
+
+// For IE8 and IE9.
+function handleEventsForInputEventIE(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topFocus) {
+ // In IE8, we can capture almost all .value changes by adding a
+ // propertychange handler and looking for events with propertyName
+ // equal to 'value'
+ // In IE9, propertychange fires for most input events but is buggy and
+ // doesn't fire when text is deleted, but conveniently, selectionchange
+ // appears to fire in all of the remaining cases so we catch those and
+ // forward the event if the value has changed
+ // In either case, we don't want to call the event handler if the value
+ // is changed from JS so we redefine a setter for `.value` that updates
+ // our activeElementValue variable, allowing us to ignore those changes
+ //
+ // stopWatching() should be a noop here but we call it just in case we
+ // missed a blur event somehow.
+ stopWatchingForValueChange();
+ startWatchingForValueChange(topLevelTarget, topLevelTargetID);
+ } else if (topLevelType === topLevelTypes.topBlur) {
+ stopWatchingForValueChange();
+ }
+}
+
+// For IE8 and IE9.
+function getTargetIDForInputEventIE(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topSelectionChange ||
+ topLevelType === topLevelTypes.topKeyUp ||
+ topLevelType === topLevelTypes.topKeyDown) {
+ // On the selectionchange event, the target is just document which isn't
+ // helpful for us so just check activeElement instead.
+ //
+ // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
+ // propertychange on the first input event after setting `value` from a
+ // script and fires only keydown, keypress, keyup. Catching keyup usually
+ // gets it and catching keydown lets us fire an event for the first
+ // keystroke if user does a key repeat (it'll be a little delayed: right
+ // before the second keystroke). Other input methods (e.g., paste) seem to
+ // fire selectionchange normally.
+ if (activeElement && activeElement.value !== activeElementValue) {
+ activeElementValue = activeElement.value;
+ return activeElementID;
+ }
+ }
+}
+
+
+/**
+ * SECTION: handle `click` event
+ */
+function shouldUseClickEvent(elem) {
+ // Use the `click` event to detect changes to checkbox and radio inputs.
+ // This approach works across all browsers, whereas `change` does not fire
+ // until `blur` in IE8.
+ return (
+ elem.nodeName === 'INPUT' &&
+ (elem.type === 'checkbox' || elem.type === 'radio')
+ );
+}
+
+function getTargetIDForClickEvent(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID) {
+ if (topLevelType === topLevelTypes.topClick) {
+ return topLevelTargetID;
+ }
+}
+
+/**
+ * This plugin creates an `onChange` event that normalizes change events
+ * across form elements. This event fires at a time when it's possible to
+ * change the element's value without seeing a flicker.
+ *
+ * Supported elements are:
+ * - input (see `supportedInputTypes`)
+ * - textarea
+ * - select
+ */
+var ChangeEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+
+ var getTargetIDFunc, handleEventFunc;
+ if (shouldUseChangeEvent(topLevelTarget)) {
+ if (doesChangeEventBubble) {
+ getTargetIDFunc = getTargetIDForChangeEvent;
+ } else {
+ handleEventFunc = handleEventsForChangeEventIE8;
+ }
+ } else if (shouldUseInputEvent(topLevelTarget)) {
+ if (isInputEventSupported) {
+ getTargetIDFunc = getTargetIDForInputEvent;
+ } else {
+ getTargetIDFunc = getTargetIDForInputEventIE;
+ handleEventFunc = handleEventsForInputEventIE;
+ }
+ } else if (shouldUseClickEvent(topLevelTarget)) {
+ getTargetIDFunc = getTargetIDForClickEvent;
+ }
+
+ if (getTargetIDFunc) {
+ var targetID = getTargetIDFunc(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID
+ );
+ if (targetID) {
+ var event = SyntheticEvent.getPooled(
+ eventTypes.change,
+ targetID,
+ nativeEvent
+ );
+ EventPropagators.accumulateTwoPhaseDispatches(event);
+ return event;
+ }
+ }
+
+ if (handleEventFunc) {
+ handleEventFunc(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID
+ );
+ }
+ }
+
+};
+
+module.exports = ChangeEventPlugin;
+
+})()
+},{"./EventConstants":13,"./EventPluginHub":15,"./EventPropagators":18,"./ExecutionEnvironment":19,"./SyntheticEvent":51,"./isEventSupported":79,"./keyOf":82}],6:[function(require,module,exports){
+(function(){/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule DOMChildrenOperations
+ */
+
+// Empty blocks improve readability so disable that warning
+// jshint -W035
+
+"use strict";
+
+var Danger = require("./Danger");
+
+var insertNodeAt = require("./insertNodeAt");
+var keyOf = require("./keyOf");
+var throwIf = require("./throwIf");
+
+var NON_INCREASING_OPERATIONS;
+if (true) {
+ NON_INCREASING_OPERATIONS =
+ 'DOM child management operations must be provided in order ' +
+ 'of increasing destination index. This is likely an issue with ' +
+ 'the core framework.';
+}
+
+var MOVE_NODE_AT_ORIG_INDEX = keyOf({moveFrom: null});
+var INSERT_MARKUP = keyOf({insertMarkup: null});
+var REMOVE_AT = keyOf({removeAt: null});
+
+/**
+ * In order to carry out movement of DOM nodes without knowing their IDs, we
+ * have to first store knowledge about nodes' original indices before beginning
+ * to carry out the sequence of operations. Once we begin the sequence, the DOM
+ * indices in future instructions are no longer valid.
+ *
+ * @param {Element} parent Parent DOM node.
+ * @param {Object} childOperations Description of child operations.
+ * @return {Array?} Sparse array containing elements by their current index in
+ * the DOM.
+ */
+var _getNodesByOriginalIndex = function(parent, childOperations) {
+ var nodesByOriginalIndex; // Sparse array.
+ var childOperation;
+ var origIndex;
+ for (var i = 0; i < childOperations.length; i++) {
+ childOperation = childOperations[i];
+ if (MOVE_NODE_AT_ORIG_INDEX in childOperation) {
+ nodesByOriginalIndex = nodesByOriginalIndex || [];
+ origIndex = childOperation.moveFrom;
+ nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex];
+ } else if (REMOVE_AT in childOperation) {
+ nodesByOriginalIndex = nodesByOriginalIndex || [];
+ origIndex = childOperation.removeAt;
+ nodesByOriginalIndex[origIndex] = parent.childNodes[origIndex];
+ }
+ }
+ return nodesByOriginalIndex;
+};
+
+/**
+ * Removes DOM elements from their parent, or moved.
+ * @param {Element} parent Parent DOM node.
+ * @param {Array} nodesByOriginalIndex Child nodes by their original index
+ * (potentially sparse.)
+ */
+var _removeChildrenByOriginalIndex = function(parent, nodesByOriginalIndex) {
+ for (var j = 0; j < nodesByOriginalIndex.length; j++) {
+ var nodeToRemove = nodesByOriginalIndex[j];
+ if (nodeToRemove) { // We used a sparse array.
+ parent.removeChild(nodesByOriginalIndex[j]);
+ }
+ }
+};
+
+/**
+ * Once all nodes that will be removed or moved - are removed from the parent
+ * node, we can begin the process of placing nodes into their final locations.
+ * We must perform all operations in the order of the final DOM index -
+ * otherwise, we couldn't count on the fact that an insertion at index X, will
+ * remain at index X. This will iterate through the child operations, adding
+ * content where needed, skip over removals (they've already been removed) and
+ * insert "moved" Elements that were previously removed. The "moved" elements
+ * are only temporarily removed from the parent, so that index calculations can
+ * be manageable and perform well in the cases that matter.
+ */
+var _placeNodesAtDestination =
+ function(parent, childOperations, nodesByOriginalIndex) {
+ var origNode;
+ var finalIndex;
+ var lastFinalIndex = -1;
+ var childOperation;
+ for (var k = 0; k < childOperations.length; k++) {
+ childOperation = childOperations[k];
+ if (MOVE_NODE_AT_ORIG_INDEX in childOperation) {
+ origNode = nodesByOriginalIndex[childOperation.moveFrom];
+ finalIndex = childOperation.finalIndex;
+ insertNodeAt(parent, origNode, finalIndex);
+ if (true) {
+ throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS);
+ lastFinalIndex = finalIndex;
+ }
+ } else if (REMOVE_AT in childOperation) {
+ } else if (INSERT_MARKUP in childOperation) {
+ finalIndex = childOperation.finalIndex;
+ var markup = childOperation.insertMarkup;
+ Danger.dangerouslyInsertMarkupAt(parent, markup, finalIndex);
+ if (true) {
+ throwIf(finalIndex <= lastFinalIndex, NON_INCREASING_OPERATIONS);
+ lastFinalIndex = finalIndex;
+ }
+ }
+ }
+ };
+
+var manageChildren = function(parent, childOperations) {
+ var nodesByOriginalIndex = _getNodesByOriginalIndex(parent, childOperations);
+ if (nodesByOriginalIndex) {
+ _removeChildrenByOriginalIndex(parent, nodesByOriginalIndex);
+ }
+ _placeNodesAtDestination(parent, childOperations, nodesByOriginalIndex);
+};
+
+/**
+ * Also reexport all of the dangerous functions. It helps to have all dangerous
+ * functions located in a single module `Danger`.
+ */
+var DOMChildrenOperations = {
+ dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,
+ manageChildren: manageChildren
+};
+
+module.exports = DOMChildrenOperations;
+
+})()
+},{"./Danger":9,"./insertNodeAt":77,"./keyOf":82,"./throwIf":89}],7:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule DOMProperty
+ * @typechecks static-only
+ */
+
+/*jslint bitwise: true */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+var DOMPropertyInjection = {
+ /**
+ * Mapping from normalized, camelcased property names to a configuration that
+ * specifies how the associated DOM property should be accessed or rendered.
+ */
+ MUST_USE_ATTRIBUTE: 0x1,
+ MUST_USE_PROPERTY: 0x2,
+ HAS_BOOLEAN_VALUE: 0x4,
+ HAS_SIDE_EFFECTS: 0x8,
+
+ /**
+ * Inject some specialized knowledge about the DOM. This takes a config object
+ * with the following properties:
+ *
+ * isCustomAttribute: function that given an attribute name will return true
+ * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
+ * attributes where it's impossible to enumerate all of the possible
+ * attribute names,
+ *
+ * Properties: object mapping DOM property name to one of the
+ * DOMPropertyInjection constants or null. If your attribute isn't in here,
+ * it won't get written to the DOM.
+ *
+ * DOMAttributeNames: object mapping React attribute name to the DOM
+ * attribute name. Attribute names not specified use the **lowercase**
+ * normalized name.
+ *
+ * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
+ * Property names not specified use the normalized name.
+ *
+ * DOMMutationMethods: Properties that require special mutation methods. If
+ * `value` is undefined, the mutation method should unset the property.
+ *
+ * @param {object} domPropertyConfig the config as described above.
+ */
+ injectDOMPropertyConfig: function(domPropertyConfig) {
+ var Properties = domPropertyConfig.Properties || {};
+ var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
+ var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
+ var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
+
+ if (domPropertyConfig.isCustomAttribute) {
+ DOMProperty._isCustomAttributeFunctions.push(
+ domPropertyConfig.isCustomAttribute
+ );
+ }
+
+ for (var propName in Properties) {
+ invariant(
+ !DOMProperty.isStandardName[propName],
+ 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
+ '\'%s\' which has already been injected. You may be accidentally ' +
+ 'injecting the same DOM property config twice, or you may be ' +
+ 'injecting two configs that have conflicting property names.',
+ propName
+ );
+
+ DOMProperty.isStandardName[propName] = true;
+
+ DOMProperty.getAttributeName[propName] =
+ DOMAttributeNames[propName] || propName.toLowerCase();
+
+ DOMProperty.getPropertyName[propName] =
+ DOMPropertyNames[propName] || propName;
+
+ var mutationMethod = DOMMutationMethods[propName];
+ if (mutationMethod) {
+ DOMProperty.getMutationMethod[propName] = mutationMethod;
+ }
+
+ var propConfig = Properties[propName];
+ DOMProperty.mustUseAttribute[propName] =
+ propConfig & DOMPropertyInjection.MUST_USE_ATTRIBUTE;
+ DOMProperty.mustUseProperty[propName] =
+ propConfig & DOMPropertyInjection.MUST_USE_PROPERTY;
+ DOMProperty.hasBooleanValue[propName] =
+ propConfig & DOMPropertyInjection.HAS_BOOLEAN_VALUE;
+ DOMProperty.hasSideEffects[propName] =
+ propConfig & DOMPropertyInjection.HAS_SIDE_EFFECTS;
+
+ invariant(
+ !DOMProperty.mustUseAttribute[propName] ||
+ !DOMProperty.mustUseProperty[propName],
+ 'DOMProperty: Cannot use require using both attribute and property: %s',
+ propName
+ );
+ invariant(
+ DOMProperty.mustUseProperty[propName] ||
+ !DOMProperty.hasSideEffects[propName],
+ 'DOMProperty: Properties that have side effects must use property: %s',
+ propName
+ );
+ }
+ }
+};
+var defaultValueCache = {};
+
+/**
+ * DOMProperty exports lookup objects that can be used like functions:
+ *
+ * > DOMProperty.isValid['id']
+ * true
+ * > DOMProperty.isValid['foobar']
+ * undefined
+ *
+ * Although this may be confusing, it performs better in general.
+ *
+ * @see http://jsperf.com/key-exists
+ * @see http://jsperf.com/key-missing
+ */
+var DOMProperty = {
+
+ /**
+ * Checks whether a property name is a standard property.
+ * @type {Object}
+ */
+ isStandardName: {},
+
+ /**
+ * Mapping from normalized names to attribute names that differ. Attribute
+ * names are used when rendering markup or with `*Attribute()`.
+ * @type {Object}
+ */
+ getAttributeName: {},
+
+ /**
+ * Mapping from normalized names to properties on DOM node instances.
+ * (This includes properties that mutate due to external factors.)
+ * @type {Object}
+ */
+ getPropertyName: {},
+
+ /**
+ * Mapping from normalized names to mutation methods. This will only exist if
+ * mutation cannot be set simply by the property or `setAttribute()`.
+ * @type {Object}
+ */
+ getMutationMethod: {},
+
+ /**
+ * Whether the property must be accessed and mutated as an object property.
+ * @type {Object}
+ */
+ mustUseAttribute: {},
+
+ /**
+ * Whether the property must be accessed and mutated using `*Attribute()`.
+ * (This includes anything that fails ` in `.)
+ * @type {Object}
+ */
+ mustUseProperty: {},
+
+ /**
+ * Whether the property should be removed when set to a falsey value.
+ * @type {Object}
+ */
+ hasBooleanValue: {},
+
+ /**
+ * Whether or not setting a value causes side effects such as triggering
+ * resources to be loaded or text selection changes. We must ensure that
+ * the value is only set if it has changed.
+ * @type {Object}
+ */
+ hasSideEffects: {},
+
+ /**
+ * All of the isCustomAttribute() functions that have been injected.
+ */
+ _isCustomAttributeFunctions: [],
+
+ /**
+ * Checks whether a property name is a custom attribute.
+ * @method
+ */
+ isCustomAttribute: function(attributeName) {
+ return DOMProperty._isCustomAttributeFunctions.some(
+ function(isCustomAttributeFn) {
+ return isCustomAttributeFn.call(null, attributeName);
+ }
+ );
+ },
+
+ /**
+ * Returns the default property value for a DOM property (i.e., not an
+ * attribute). Most default values are '' or false, but not all. Worse yet,
+ * some (in particular, `type`) vary depending on the type of element.
+ *
+ * TODO: Is it better to grab all the possible properties when creating an
+ * element to avoid having to create the same element twice?
+ */
+ getDefaultValueForProperty: function(nodeName, prop) {
+ var nodeDefaults = defaultValueCache[nodeName];
+ var testElement;
+ if (!nodeDefaults) {
+ defaultValueCache[nodeName] = nodeDefaults = {};
+ }
+ if (!(prop in nodeDefaults)) {
+ testElement = document.createElement(nodeName);
+ nodeDefaults[prop] = testElement[prop];
+ }
+ return nodeDefaults[prop];
+ },
+
+ injection: DOMPropertyInjection
+};
+
+module.exports = DOMProperty;
+
+},{"./invariant":78}],8:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule DOMPropertyOperations
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+
+var escapeTextForBrowser = require("./escapeTextForBrowser");
+var memoizeStringOnly = require("./memoizeStringOnly");
+
+var processAttributeNameAndPrefix = memoizeStringOnly(function(name) {
+ return escapeTextForBrowser(name) + '="';
+});
+
+/**
+ * Operations for dealing with DOM properties.
+ */
+var DOMPropertyOperations = {
+
+ /**
+ * Creates markup for a property.
+ *
+ * @param {string} name
+ * @param {*} value
+ * @return {?string} Markup string, or null if the property was invalid.
+ */
+ createMarkupForProperty: function(name, value) {
+ if (DOMProperty.isStandardName[name]) {
+ if (value == null || DOMProperty.hasBooleanValue[name] && !value) {
+ return '';
+ }
+ var attributeName = DOMProperty.getAttributeName[name];
+ return processAttributeNameAndPrefix(attributeName) +
+ escapeTextForBrowser(value) + '"';
+ } else if (DOMProperty.isCustomAttribute(name)) {
+ if (value == null) {
+ return '';
+ }
+ return processAttributeNameAndPrefix(name) +
+ escapeTextForBrowser(value) + '"';
+ } else {
+ return null;
+ }
+ },
+
+ /**
+ * Sets the value for a property on a node.
+ *
+ * @param {DOMElement} node
+ * @param {string} name
+ * @param {*} value
+ */
+ setValueForProperty: function(node, name, value) {
+ if (DOMProperty.isStandardName[name]) {
+ var mutationMethod = DOMProperty.getMutationMethod[name];
+ if (mutationMethod) {
+ mutationMethod(node, value);
+ } else if (DOMProperty.mustUseAttribute[name]) {
+ if (DOMProperty.hasBooleanValue[name] && !value) {
+ node.removeAttribute(DOMProperty.getAttributeName[name]);
+ } else {
+ node.setAttribute(DOMProperty.getAttributeName[name], value);
+ }
+ } else {
+ var propName = DOMProperty.getPropertyName[name];
+ if (!DOMProperty.hasSideEffects[name] || node[propName] !== value) {
+ node[propName] = value;
+ }
+ }
+ } else if (DOMProperty.isCustomAttribute(name)) {
+ node.setAttribute(name, value);
+ }
+ },
+
+ /**
+ * Deletes the value for a property on a node.
+ *
+ * @param {DOMElement} node
+ * @param {string} name
+ */
+ deleteValueForProperty: function(node, name) {
+ if (DOMProperty.isStandardName[name]) {
+ var mutationMethod = DOMProperty.getMutationMethod[name];
+ if (mutationMethod) {
+ mutationMethod(node, undefined);
+ } else if (DOMProperty.mustUseAttribute[name]) {
+ node.removeAttribute(DOMProperty.getAttributeName[name]);
+ } else {
+ var propName = DOMProperty.getPropertyName[name];
+ node[propName] = DOMProperty.getDefaultValueForProperty(
+ node.nodeName,
+ name
+ );
+ }
+ } else if (DOMProperty.isCustomAttribute(name)) {
+ node.removeAttribute(name);
+ }
+ }
+
+};
+
+module.exports = DOMPropertyOperations;
+
+},{"./DOMProperty":7,"./escapeTextForBrowser":67,"./memoizeStringOnly":83}],9:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule Danger
+ */
+
+/*jslint evil: true, sub: true */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var throwIf = require("./throwIf");
+
+var DOM_UNSUPPORTED;
+var NO_MARKUP_PARENT;
+var NO_MULTI_MARKUP;
+if (true) {
+ DOM_UNSUPPORTED =
+ 'You may not insert markup into the document while you are in a worker ' +
+ 'thread. It\'s not you, it\'s me. This is likely the fault of the ' +
+ 'framework. Please report this immediately.';
+ NO_MARKUP_PARENT =
+ 'You have attempted to inject markup without a suitable parent. This is ' +
+ 'likely the fault of the framework - please report immediately.';
+ NO_MULTI_MARKUP =
+ 'The framework has attempted to either insert zero or multiple markup ' +
+ 'roots into a single location when it should not. This is a serious ' +
+ 'error - a fault of the framework - please report immediately.';
+}
+
+var validateMarkupParams;
+if (true) {
+ validateMarkupParams = function(parentNode, markup) {
+ throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED);
+ throwIf(!parentNode || !parentNode.tagName, NO_MARKUP_PARENT);
+ throwIf(!markup, NO_MULTI_MARKUP);
+ };
+}
+
+/**
+ * Dummy container used to render all markup.
+ */
+var dummyNode = ExecutionEnvironment.canUseDOM ?
+ document.createElement('div') :
+ null;
+
+/**
+ * Some browsers cannot use `innerHTML` to render certain elements standalone,
+ * so we wrap them, render the wrapped nodes, then extract the desired node.
+ */
+var markupWrap = {
+ 'option': [1, ''],
+ 'legend': [1, ''],
+ 'area': [1, ''],
+ 'param': [1, ''],
+ 'thead': [1, '
', '
'],
+ 'tr': [2, '
', '
'],
+ 'col': [2, '
', '
'],
+ 'td': [3, '
', '
']
+};
+markupWrap['optgroup'] = markupWrap['option'];
+markupWrap['tbody'] = markupWrap['thead'];
+markupWrap['tfoot'] = markupWrap['thead'];
+markupWrap['colgroup'] = markupWrap['thead'];
+markupWrap['caption'] = markupWrap['thead'];
+markupWrap['th'] = markupWrap['td'];
+
+/**
+ * In IE8, certain elements cannot render alone, so wrap all elements.
+ */
+var defaultWrap = [1, '?
', '
'];
+
+/**
+ * Feature detection, remove wraps that are unnecessary for the current browser.
+ */
+if (dummyNode) {
+ for (var nodeName in markupWrap) {
+ if (!markupWrap.hasOwnProperty(nodeName)) {
+ continue;
+ }
+ dummyNode.innerHTML = '<' + nodeName + '>' + nodeName + '>';
+ if (dummyNode.firstChild) {
+ markupWrap[nodeName] = null;
+ }
+ }
+ dummyNode.innerHTML = '';
+ if (dummyNode.firstChild) {
+ defaultWrap = null;
+ }
+}
+
+/**
+ * Renders markup into nodes. The returned HTMLCollection is live and should be
+ * used immediately (or at least before the next invocation to `renderMarkup`).
+ *
+ * NOTE: Extracting the `nodeName` does not require a regular expression match
+ * because we make assumptions about React-generated markup (i.e. there are no
+ * spaces surrounding the opening tag and there is at least one attribute).
+ * @see http://jsperf.com/extract-nodename
+ *
+ * @param {string} markup
+ * @return {*} An HTMLCollection.
+ */
+function renderMarkup(markup) {
+ var node = dummyNode;
+ var nodeName = markup.substring(1, markup.indexOf(' '));
+
+ var wrap = markupWrap[nodeName.toLowerCase()] || defaultWrap;
+ if (wrap) {
+ node.innerHTML = wrap[1] + markup + wrap[2];
+
+ var wrapDepth = wrap[0];
+ while (wrapDepth--) {
+ node = node.lastChild;
+ }
+ } else {
+ node.innerHTML = markup;
+ }
+ return node.childNodes;
+}
+
+/**
+ * Inserts node after 'after'. If 'after' is null, inserts it after nothing,
+ * which is inserting it at the beginning.
+ *
+ * @param {Element} elem Parent element.
+ * @param {Element} insert Element to insert.
+ * @param {Element} after Element to insert after.
+ * @return {Element} Element that was inserted.
+ */
+function insertNodeAfterNode(elem, insert, after) {
+ if (true) {
+ throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED);
+ }
+ if (after) {
+ if (after.nextSibling) {
+ return elem.insertBefore(insert, after.nextSibling);
+ } else {
+ return elem.appendChild(insert);
+ }
+ } else {
+ return elem.insertBefore(insert, elem.firstChild);
+ }
+}
+
+/**
+ * Slow: Should only be used when it is known there are a few (or one) element
+ * in the node list.
+ * @param {Element} parentRootDomNode Parent element.
+ * @param {HTMLCollection} htmlCollection HTMLCollection to insert.
+ * @param {Element} after Element to insert the node list after.
+ */
+function inefficientlyInsertHTMLCollectionAfter(
+ parentRootDomNode,
+ htmlCollection,
+ after) {
+
+ if (true) {
+ throwIf(!ExecutionEnvironment.canUseDOM, DOM_UNSUPPORTED);
+ }
+ var ret;
+ var originalLength = htmlCollection.length;
+ // Access htmlCollection[0] because htmlCollection shrinks as we remove items.
+ // `insertNodeAfterNode` will remove items from the htmlCollection.
+ for (var i = 0; i < originalLength; i++) {
+ ret =
+ insertNodeAfterNode(parentRootDomNode, htmlCollection[0], ret || after);
+ }
+}
+
+/**
+ * Super-dangerously inserts markup into existing DOM structure. Seriously, you
+ * don't want to use this module unless you are building a framework. This
+ * requires that the markup that you are inserting represents the root of a
+ * tree. We do not support the case where there `markup` represents several
+ * roots.
+ *
+ * @param {Element} parentNode Parent DOM element.
+ * @param {string} markup Markup to dangerously insert.
+ * @param {number} index Position to insert markup at.
+ */
+function dangerouslyInsertMarkupAt(parentNode, markup, index) {
+ if (true) {
+ validateMarkupParams(parentNode, markup);
+ }
+ var htmlCollection = renderMarkup(markup);
+ var afterNode = index ? parentNode.childNodes[index - 1] : null;
+ inefficientlyInsertHTMLCollectionAfter(parentNode, htmlCollection, afterNode);
+}
+
+/**
+ * Replaces a node with a string of markup at its current position within its
+ * parent. `childNode` must be in the document (or at least within a parent
+ * node). The string of markup must represent a tree of markup with a single
+ * root.
+ *
+ * @param {Element} childNode Child node to replace.
+ * @param {string} markup Markup to dangerously replace child with.
+ */
+function dangerouslyReplaceNodeWithMarkup(childNode, markup) {
+ var parentNode = childNode.parentNode;
+ if (true) {
+ validateMarkupParams(parentNode, markup);
+ }
+ var htmlCollection = renderMarkup(markup);
+ if (true) {
+ throwIf(htmlCollection.length !== 1, NO_MULTI_MARKUP);
+ }
+ parentNode.replaceChild(htmlCollection[0], childNode);
+}
+
+var Danger = {
+ dangerouslyInsertMarkupAt: dangerouslyInsertMarkupAt,
+ dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup
+};
+
+module.exports = Danger;
+
+},{"./ExecutionEnvironment":19,"./throwIf":89}],10:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule DefaultDOMPropertyConfig
+ */
+
+"use strict";
+
+var DOMProperty = require("./DOMProperty");
+
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
+var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
+var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
+var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
+
+var DefaultDOMPropertyConfig = {
+ isCustomAttribute: RegExp.prototype.test.bind(
+ /^(data|aria)-[a-z_][a-z\d_.\-]*$/
+ ),
+ Properties: {
+ /**
+ * Standard Properties
+ */
+ accessKey: null,
+ accept: null,
+ action: null,
+ ajaxify: MUST_USE_ATTRIBUTE,
+ allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+ allowTransparency: MUST_USE_ATTRIBUTE,
+ alt: null,
+ autoComplete: null,
+ autoFocus: HAS_BOOLEAN_VALUE,
+ autoPlay: HAS_BOOLEAN_VALUE,
+ cellPadding: null,
+ cellSpacing: null,
+ checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ className: MUST_USE_PROPERTY,
+ colSpan: null,
+ contentEditable: null,
+ contextMenu: MUST_USE_ATTRIBUTE,
+ controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ data: null, // For `` acts as `src`.
+ dateTime: MUST_USE_ATTRIBUTE,
+ dir: null,
+ disabled: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ draggable: null,
+ encType: null,
+ frameBorder: MUST_USE_ATTRIBUTE,
+ height: MUST_USE_ATTRIBUTE,
+ hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+ href: null,
+ htmlFor: null,
+ icon: null,
+ id: MUST_USE_PROPERTY,
+ label: null,
+ lang: null,
+ list: null,
+ max: null,
+ maxLength: MUST_USE_ATTRIBUTE,
+ method: null,
+ min: null,
+ multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ name: null,
+ pattern: null,
+ poster: null,
+ preload: null,
+ placeholder: null,
+ radioGroup: null,
+ rel: null,
+ readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ required: HAS_BOOLEAN_VALUE,
+ role: MUST_USE_ATTRIBUTE,
+ scrollLeft: MUST_USE_PROPERTY,
+ scrollTop: MUST_USE_PROPERTY,
+ selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ size: null,
+ spellCheck: null,
+ src: null,
+ step: null,
+ style: null,
+ tabIndex: null,
+ target: null,
+ title: null,
+ type: null,
+ value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
+ width: MUST_USE_ATTRIBUTE,
+ wmode: MUST_USE_ATTRIBUTE,
+ /**
+ * SVG Properties
+ */
+ cx: MUST_USE_PROPERTY,
+ cy: MUST_USE_PROPERTY,
+ d: MUST_USE_PROPERTY,
+ fill: MUST_USE_PROPERTY,
+ fx: MUST_USE_PROPERTY,
+ fy: MUST_USE_PROPERTY,
+ points: MUST_USE_PROPERTY,
+ r: MUST_USE_PROPERTY,
+ stroke: MUST_USE_PROPERTY,
+ strokeLinecap: MUST_USE_PROPERTY,
+ strokeWidth: MUST_USE_PROPERTY,
+ transform: MUST_USE_PROPERTY,
+ x: MUST_USE_PROPERTY,
+ x1: MUST_USE_PROPERTY,
+ x2: MUST_USE_PROPERTY,
+ version: MUST_USE_PROPERTY,
+ viewBox: MUST_USE_PROPERTY,
+ y: MUST_USE_PROPERTY,
+ y1: MUST_USE_PROPERTY,
+ y2: MUST_USE_PROPERTY,
+ spreadMethod: MUST_USE_PROPERTY,
+ offset: MUST_USE_PROPERTY,
+ stopColor: MUST_USE_PROPERTY,
+ stopOpacity: MUST_USE_PROPERTY,
+ gradientUnits: MUST_USE_PROPERTY,
+ gradientTransform: MUST_USE_PROPERTY
+ },
+ DOMAttributeNames: {
+ className: 'class',
+ htmlFor: 'for',
+ strokeLinecap: 'stroke-linecap',
+ strokeWidth: 'stroke-width',
+ stopColor: 'stop-color',
+ stopOpacity: 'stop-opacity'
+ },
+ DOMPropertyNames: {
+ autoComplete: 'autocomplete',
+ autoFocus: 'autofocus',
+ autoPlay: 'autoplay',
+ encType: 'enctype',
+ radioGroup: 'radiogroup',
+ spellCheck: 'spellcheck'
+ },
+ DOMMutationMethods: {
+ /**
+ * Setting `className` to null may cause it to be set to the string "null".
+ *
+ * @param {DOMElement} node
+ * @param {*} value
+ */
+ className: function(node, value) {
+ node.className = value || '';
+ }
+ }
+};
+
+module.exports = DefaultDOMPropertyConfig;
+
+},{"./DOMProperty":7}],11:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule DefaultEventPluginOrder
+ */
+
+"use strict";
+
+ var keyOf = require("./keyOf");
+
+/**
+ * Module that is injectable into `EventPluginHub`, that specifies a
+ * deterministic ordering of `EventPlugin`s. A convenient way to reason about
+ * plugins, without having to package every one of them. This is better than
+ * having plugins be ordered in the same order that they are injected because
+ * that ordering would be influenced by the packaging order.
+ * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
+ * preventing default on events is convenient in `SimpleEventPlugin` handlers.
+ */
+var DefaultEventPluginOrder = [
+ keyOf({ResponderEventPlugin: null}),
+ keyOf({SimpleEventPlugin: null}),
+ keyOf({TapEventPlugin: null}),
+ keyOf({EnterLeaveEventPlugin: null}),
+ keyOf({ChangeEventPlugin: null}),
+ keyOf({AnalyticsEventPlugin: null}),
+ keyOf({MobileSafariClickEventPlugin: null})
+];
+
+module.exports = DefaultEventPluginOrder;
+
+},{"./keyOf":82}],12:[function(require,module,exports){
+(function(){/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EnterLeaveEventPlugin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+
+var ReactMount = require("./ReactMount");
+var keyOf = require("./keyOf");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+var getFirstReactDOM = ReactMount.getFirstReactDOM;
+
+var eventTypes = {
+ mouseEnter: {registrationName: keyOf({onMouseEnter: null})},
+ mouseLeave: {registrationName: keyOf({onMouseLeave: null})}
+};
+
+var EnterLeaveEventPlugin = {
+
+ eventTypes: eventTypes,
+
+ /**
+ * For almost every interaction we care about, there will be both a top-level
+ * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
+ * we do not extract duplicate events. However, moving the mouse into the
+ * browser from outside will not fire a `mouseout` event. In this case, we use
+ * the `mouseover` top-level event.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ if (topLevelType === topLevelTypes.topMouseOver &&
+ (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
+ return null;
+ }
+ if (topLevelType !== topLevelTypes.topMouseOut &&
+ topLevelType !== topLevelTypes.topMouseOver) {
+ // Must not be a mouse in or mouse out - ignoring.
+ return null;
+ }
+
+ var from, to;
+ if (topLevelType === topLevelTypes.topMouseOut) {
+ from = topLevelTarget;
+ to =
+ getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
+ ExecutionEnvironment.global;
+ } else {
+ from = ExecutionEnvironment.global;
+ to = topLevelTarget;
+ }
+
+ if (from === to) {
+ // Nothing pertains to our managed components.
+ return null;
+ }
+
+ var fromID = from ? ReactMount.getID(from) : '';
+ var toID = to ? ReactMount.getID(to) : '';
+
+ var leave = SyntheticMouseEvent.getPooled(
+ eventTypes.mouseLeave,
+ fromID,
+ nativeEvent
+ );
+ var enter = SyntheticMouseEvent.getPooled(
+ eventTypes.mouseEnter,
+ toID,
+ nativeEvent
+ );
+
+ EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
+ return [leave, enter];
+ }
+
+};
+
+module.exports = EnterLeaveEventPlugin;
+
+})()
+},{"./EventConstants":13,"./EventPropagators":18,"./ExecutionEnvironment":19,"./ReactMount":39,"./SyntheticMouseEvent":54,"./keyOf":82}],13:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventConstants
+ */
+
+"use strict";
+
+var keyMirror = require("./keyMirror");
+
+var PropagationPhases = keyMirror({bubbled: null, captured: null});
+
+/**
+ * Types of raw signals from the browser caught at the top level.
+ */
+var topLevelTypes = keyMirror({
+ topBlur: null,
+ topChange: null,
+ topClick: null,
+ topDOMCharacterDataModified: null,
+ topDoubleClick: null,
+ topDrag: null,
+ topDragEnd: null,
+ topDragEnter: null,
+ topDragExit: null,
+ topDragLeave: null,
+ topDragOver: null,
+ topDragStart: null,
+ topDrop: null,
+ topFocus: null,
+ topInput: null,
+ topKeyDown: null,
+ topKeyPress: null,
+ topKeyUp: null,
+ topMouseDown: null,
+ topMouseMove: null,
+ topMouseOut: null,
+ topMouseOver: null,
+ topMouseUp: null,
+ topScroll: null,
+ topSelectionChange: null,
+ topSubmit: null,
+ topTouchCancel: null,
+ topTouchEnd: null,
+ topTouchMove: null,
+ topTouchStart: null,
+ topWheel: null
+});
+
+var EventConstants = {
+ topLevelTypes: topLevelTypes,
+ PropagationPhases: PropagationPhases
+};
+
+module.exports = EventConstants;
+
+},{"./keyMirror":81}],14:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventListener
+ */
+
+/**
+ * Upstream version of event listener. Does not take into account specific
+ * nature of platform.
+ */
+var EventListener = {
+ /**
+ * Listens to bubbled events on a DOM node.
+ *
+ * @param {Element} el DOM element to register listener on.
+ * @param {string} handlerBaseName 'click'/'mouseover'
+ * @param {Function!} cb Callback function
+ */
+ listen: function(el, handlerBaseName, cb) {
+ if (el.addEventListener) {
+ el.addEventListener(handlerBaseName, cb, false);
+ } else if (el.attachEvent) {
+ el.attachEvent('on' + handlerBaseName, cb);
+ }
+ },
+
+ /**
+ * Listens to captured events on a DOM node.
+ *
+ * @see `EventListener.listen` for params.
+ * @throws Exception if addEventListener is not supported.
+ */
+ capture: function(el, handlerBaseName, cb) {
+ if (!el.addEventListener) {
+ if (true) {
+ console.error(
+ 'You are attempting to use addEventlistener ' +
+ 'in a browser that does not support it support it.' +
+ 'This likely means that you will not receive events that ' +
+ 'your application relies on (such as scroll).');
+ }
+ return;
+ } else {
+ el.addEventListener(handlerBaseName, cb, true);
+ }
+ }
+};
+
+module.exports = EventListener;
+
+},{}],15:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventPluginHub
+ */
+
+"use strict";
+
+var CallbackRegistry = require("./CallbackRegistry");
+var EventPluginRegistry = require("./EventPluginRegistry");
+var EventPluginUtils = require("./EventPluginUtils");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var accumulate = require("./accumulate");
+var forEachAccumulated = require("./forEachAccumulated");
+var invariant = require("./invariant");
+
+/**
+ * Internal queue of events that have accumulated their dispatches and are
+ * waiting to have their dispatches executed.
+ */
+var eventQueue = null;
+
+/**
+ * Dispatches an event and releases it back into the pool, unless persistent.
+ *
+ * @param {?object} event Synthetic event to be dispatched.
+ * @private
+ */
+var executeDispatchesAndRelease = function(event) {
+ if (event) {
+ var executeDispatch = EventPluginUtils.executeDispatch;
+ // Plugins can provide custom behavior when dispatching events.
+ var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event);
+ if (PluginModule && PluginModule.executeDispatch) {
+ executeDispatch = PluginModule.executeDispatch;
+ }
+ EventPluginUtils.executeDispatchesInOrder(event, executeDispatch);
+
+ if (!event.isPersistent()) {
+ event.constructor.release(event);
+ }
+ }
+};
+
+/**
+ * This is a unified interface for event plugins to be installed and configured.
+ *
+ * Event plugins can implement the following properties:
+ *
+ * `extractEvents` {function(string, DOMEventTarget, string, object): *}
+ * Required. When a top-level event is fired, this method is expected to
+ * extract synthetic events that will in turn be queued and dispatched.
+ *
+ * `eventTypes` {object}
+ * Optional, plugins that fire events must publish a mapping of registration
+ * names that are used to register listeners. Values of this mapping must
+ * be objects that contain `registrationName` or `phasedRegistrationNames`.
+ *
+ * `executeDispatch` {function(object, function, string)}
+ * Optional, allows plugins to override how an event gets dispatched. By
+ * default, the listener is simply invoked.
+ *
+ * Each plugin that is injected into `EventsPluginHub` is immediately operable.
+ *
+ * @public
+ */
+var EventPluginHub = {
+
+ /**
+ * Methods for injecting dependencies.
+ */
+ injection: {
+
+ /**
+ * @param {object} InjectedInstanceHandle
+ * @public
+ */
+ injectInstanceHandle: EventPropagators.injection.injectInstanceHandle,
+
+ /**
+ * @param {array} InjectedEventPluginOrder
+ * @public
+ */
+ injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
+
+ /**
+ * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+ */
+ injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
+
+ },
+
+ registrationNames: EventPluginRegistry.registrationNames,
+
+ putListener: CallbackRegistry.putListener,
+
+ getListener: CallbackRegistry.getListener,
+
+ deleteListener: CallbackRegistry.deleteListener,
+
+ deleteAllListeners: CallbackRegistry.deleteAllListeners,
+
+ /**
+ * Allows registered plugins an opportunity to extract events from top-level
+ * native browser events.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @internal
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ var events;
+ var plugins = EventPluginRegistry.plugins;
+ for (var i = 0, l = plugins.length; i < l; i++) {
+ // Not every plugin in the ordering may be loaded at runtime.
+ var possiblePlugin = plugins[i];
+ if (possiblePlugin) {
+ var extractedEvents = possiblePlugin.extractEvents(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent
+ );
+ if (extractedEvents) {
+ events = accumulate(events, extractedEvents);
+ }
+ }
+ }
+ return events;
+ },
+
+ /**
+ * Enqueues a synthetic event that should be dispatched when
+ * `processEventQueue` is invoked.
+ *
+ * @param {*} events An accumulation of synthetic events.
+ * @internal
+ */
+ enqueueEvents: function(events) {
+ if (events) {
+ eventQueue = accumulate(eventQueue, events);
+ }
+ },
+
+ /**
+ * Dispatches all synthetic events on the event queue.
+ *
+ * @internal
+ */
+ processEventQueue: function() {
+ // Set `eventQueue` to null before processing it so that we can tell if more
+ // events get enqueued while processing.
+ var processingEventQueue = eventQueue;
+ eventQueue = null;
+ forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
+ invariant(
+ !eventQueue,
+ 'processEventQueue(): Additional events were enqueued while processing ' +
+ 'an event queue. Support for this has not yet been implemented.'
+ );
+ }
+
+};
+
+if (ExecutionEnvironment.canUseDOM) {
+ window.EventPluginHub = EventPluginHub;
+}
+
+module.exports = EventPluginHub;
+
+},{"./CallbackRegistry":4,"./EventPluginRegistry":16,"./EventPluginUtils":17,"./EventPropagators":18,"./ExecutionEnvironment":19,"./accumulate":61,"./forEachAccumulated":70,"./invariant":78}],16:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventPluginRegistry
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var invariant = require("./invariant");
+
+/**
+ * Injectable ordering of event plugins.
+ */
+var EventPluginOrder = null;
+
+/**
+ * Injectable mapping from names to event plugin modules.
+ */
+var namesToPlugins = {};
+
+/**
+ * Recomputes the plugin list using the injected plugins and plugin ordering.
+ *
+ * @private
+ */
+function recomputePluginOrdering() {
+ if (!EventPluginOrder) {
+ // Wait until an `EventPluginOrder` is injected.
+ return;
+ }
+ for (var pluginName in namesToPlugins) {
+ var PluginModule = namesToPlugins[pluginName];
+ var pluginIndex = EventPluginOrder.indexOf(pluginName);
+ invariant(
+ pluginIndex > -1,
+ 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
+ 'the plugin ordering, `%s`.',
+ pluginName
+ );
+ if (EventPluginRegistry.plugins[pluginIndex]) {
+ continue;
+ }
+ invariant(
+ PluginModule.extractEvents,
+ 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
+ 'method, but `%s` does not.',
+ pluginName
+ );
+ EventPluginRegistry.plugins[pluginIndex] = PluginModule;
+ var publishedEvents = PluginModule.eventTypes;
+ for (var eventName in publishedEvents) {
+ invariant(
+ publishEventForPlugin(publishedEvents[eventName], PluginModule),
+ 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
+ eventName,
+ pluginName
+ );
+ }
+ }
+}
+
+/**
+ * Publishes an event so that it can be dispatched by the supplied plugin.
+ *
+ * @param {object} dispatchConfig Dispatch configuration for the event.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @return {boolean} True if the event was successfully published.
+ * @private
+ */
+function publishEventForPlugin(dispatchConfig, PluginModule) {
+ var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
+ if (phasedRegistrationNames) {
+ for (var phaseName in phasedRegistrationNames) {
+ if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
+ var phasedRegistrationName = phasedRegistrationNames[phaseName];
+ publishRegistrationName(phasedRegistrationName, PluginModule);
+ }
+ }
+ return true;
+ } else if (dispatchConfig.registrationName) {
+ publishRegistrationName(dispatchConfig.registrationName, PluginModule);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Publishes a registration name that is used to identify dispatched events and
+ * can be used with `EventPluginHub.putListener` to register listeners.
+ *
+ * @param {string} registrationName Registration name to add.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @private
+ */
+function publishRegistrationName(registrationName, PluginModule) {
+ invariant(
+ !EventPluginRegistry.registrationNames[registrationName],
+ 'EventPluginHub: More than one plugin attempted to publish the same ' +
+ 'registration name, `%s`.',
+ registrationName
+ );
+ EventPluginRegistry.registrationNames[registrationName] = PluginModule;
+ EventPluginRegistry.registrationNamesKeys.push(registrationName);
+}
+
+/**
+ * Registers plugins so that they can extract and dispatch events.
+ *
+ * @see {EventPluginHub}
+ */
+var EventPluginRegistry = {
+
+ /**
+ * Ordered list of injected plugins.
+ */
+ plugins: [],
+
+ /**
+ * Mapping from registration names to plugin modules.
+ */
+ registrationNames: {},
+
+ /**
+ * The keys of `registrationNames`.
+ */
+ registrationNamesKeys: [],
+
+ /**
+ * Injects an ordering of plugins (by plugin name). This allows the ordering
+ * to be decoupled from injection of the actual plugins so that ordering is
+ * always deterministic regardless of packaging, on-the-fly injection, etc.
+ *
+ * @param {array} InjectedEventPluginOrder
+ * @internal
+ * @see {EventPluginHub.injection.injectEventPluginOrder}
+ */
+ injectEventPluginOrder: function(InjectedEventPluginOrder) {
+ invariant(
+ !EventPluginOrder,
+ 'EventPluginRegistry: Cannot inject event plugin ordering more than once.'
+ );
+ // Clone the ordering so it cannot be dynamically mutated.
+ EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder);
+ recomputePluginOrdering();
+ },
+
+ /**
+ * Injects plugins to be used by `EventPluginHub`. The plugin names must be
+ * in the ordering injected by `injectEventPluginOrder`.
+ *
+ * Plugins can be injected as part of page initialization or on-the-fly.
+ *
+ * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+ * @internal
+ * @see {EventPluginHub.injection.injectEventPluginsByName}
+ */
+ injectEventPluginsByName: function(injectedNamesToPlugins) {
+ var isOrderingDirty = false;
+ for (var pluginName in injectedNamesToPlugins) {
+ if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
+ continue;
+ }
+ var PluginModule = injectedNamesToPlugins[pluginName];
+ if (namesToPlugins[pluginName] !== PluginModule) {
+ invariant(
+ !namesToPlugins[pluginName],
+ 'EventPluginRegistry: Cannot inject two different event plugins ' +
+ 'using the same name, `%s`.',
+ pluginName
+ );
+ namesToPlugins[pluginName] = PluginModule;
+ isOrderingDirty = true;
+ }
+ }
+ if (isOrderingDirty) {
+ recomputePluginOrdering();
+ }
+ },
+
+ /**
+ * Looks up the plugin for the supplied event.
+ *
+ * @param {object} event A synthetic event.
+ * @return {?object} The plugin that created the supplied event.
+ * @internal
+ */
+ getPluginModuleForEvent: function(event) {
+ var dispatchConfig = event.dispatchConfig;
+ if (dispatchConfig.registrationName) {
+ return EventPluginRegistry.registrationNames[
+ dispatchConfig.registrationName
+ ] || null;
+ }
+ for (var phase in dispatchConfig.phasedRegistrationNames) {
+ if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
+ continue;
+ }
+ var PluginModule = EventPluginRegistry.registrationNames[
+ dispatchConfig.phasedRegistrationNames[phase]
+ ];
+ if (PluginModule) {
+ return PluginModule;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Exposed for unit testing.
+ * @private
+ */
+ _resetEventPlugins: function() {
+ EventPluginOrder = null;
+ for (var pluginName in namesToPlugins) {
+ if (namesToPlugins.hasOwnProperty(pluginName)) {
+ delete namesToPlugins[pluginName];
+ }
+ }
+ EventPluginRegistry.plugins.length = 0;
+ var registrationNames = EventPluginRegistry.registrationNames;
+ for (var registrationName in registrationNames) {
+ if (registrationNames.hasOwnProperty(registrationName)) {
+ delete registrationNames[registrationName];
+ }
+ }
+ EventPluginRegistry.registrationNamesKeys.length = 0;
+ }
+
+};
+
+module.exports = EventPluginRegistry;
+
+},{"./invariant":78}],17:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventPluginUtils
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+
+var invariant = require("./invariant");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+function isEndish(topLevelType) {
+ return topLevelType === topLevelTypes.topMouseUp ||
+ topLevelType === topLevelTypes.topTouchEnd ||
+ topLevelType === topLevelTypes.topTouchCancel;
+}
+
+function isMoveish(topLevelType) {
+ return topLevelType === topLevelTypes.topMouseMove ||
+ topLevelType === topLevelTypes.topTouchMove;
+}
+function isStartish(topLevelType) {
+ return topLevelType === topLevelTypes.topMouseDown ||
+ topLevelType === topLevelTypes.topTouchStart;
+}
+
+var validateEventDispatches;
+if (true) {
+ validateEventDispatches = function(event) {
+ var dispatchListeners = event._dispatchListeners;
+ var dispatchIDs = event._dispatchIDs;
+
+ var listenersIsArr = Array.isArray(dispatchListeners);
+ var idsIsArr = Array.isArray(dispatchIDs);
+ var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
+ var listenersLen = listenersIsArr ?
+ dispatchListeners.length :
+ dispatchListeners ? 1 : 0;
+
+ invariant(
+ idsIsArr === listenersIsArr && IDsLen === listenersLen,
+ 'EventPluginUtils: Invalid `event`.'
+ );
+ };
+}
+
+/**
+ * Invokes `cb(event, listener, id)`. Avoids using call if no scope is
+ * provided. The `(listener,id)` pair effectively forms the "dispatch" but are
+ * kept separate to conserve memory.
+ */
+function forEachEventDispatch(event, cb) {
+ var dispatchListeners = event._dispatchListeners;
+ var dispatchIDs = event._dispatchIDs;
+ if (true) {
+ validateEventDispatches(event);
+ }
+ if (Array.isArray(dispatchListeners)) {
+ for (var i = 0; i < dispatchListeners.length; i++) {
+ if (event.isPropagationStopped()) {
+ break;
+ }
+ // Listeners and IDs are two parallel arrays that are always in sync.
+ cb(event, dispatchListeners[i], dispatchIDs[i]);
+ }
+ } else if (dispatchListeners) {
+ cb(event, dispatchListeners, dispatchIDs);
+ }
+}
+
+/**
+ * Default implementation of PluginModule.executeDispatch().
+ * @param {SyntheticEvent} SyntheticEvent to handle
+ * @param {function} Application-level callback
+ * @param {string} domID DOM id to pass to the callback.
+ */
+function executeDispatch(event, listener, domID) {
+ listener(event, domID);
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches.
+ */
+function executeDispatchesInOrder(event, executeDispatch) {
+ forEachEventDispatch(event, executeDispatch);
+ event._dispatchListeners = null;
+ event._dispatchIDs = null;
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches, but stops
+ * at the first dispatch execution returning true, and returns that id.
+ *
+ * @return id of the first dispatch execution who's listener returns true, or
+ * null if no listener returned true.
+ */
+function executeDispatchesInOrderStopAtTrue(event) {
+ var dispatchListeners = event._dispatchListeners;
+ var dispatchIDs = event._dispatchIDs;
+ if (true) {
+ validateEventDispatches(event);
+ }
+ if (Array.isArray(dispatchListeners)) {
+ for (var i = 0; i < dispatchListeners.length; i++) {
+ if (event.isPropagationStopped()) {
+ break;
+ }
+ // Listeners and IDs are two parallel arrays that are always in sync.
+ if (dispatchListeners[i](event, dispatchIDs[i])) {
+ return dispatchIDs[i];
+ }
+ }
+ } else if (dispatchListeners) {
+ if (dispatchListeners(event, dispatchIDs)) {
+ return dispatchIDs;
+ }
+ }
+ return null;
+}
+
+/**
+ * Execution of a "direct" dispatch - there must be at most one dispatch
+ * accumulated on the event or it is considered an error. It doesn't really make
+ * sense for an event with multiple dispatches (bubbled) to keep track of the
+ * return values at each dispatch execution, but it does tend to make sense when
+ * dealing with "direct" dispatches.
+ *
+ * @return The return value of executing the single dispatch.
+ */
+function executeDirectDispatch(event) {
+ if (true) {
+ validateEventDispatches(event);
+ }
+ var dispatchListener = event._dispatchListeners;
+ var dispatchID = event._dispatchIDs;
+ invariant(
+ !Array.isArray(dispatchListener),
+ 'executeDirectDispatch(...): Invalid `event`.'
+ );
+ var res = dispatchListener ?
+ dispatchListener(event, dispatchID) :
+ null;
+ event._dispatchListeners = null;
+ event._dispatchIDs = null;
+ return res;
+}
+
+/**
+ * @param {SyntheticEvent} event
+ * @return {bool} True iff number of dispatches accumulated is greater than 0.
+ */
+function hasDispatches(event) {
+ return !!event._dispatchListeners;
+}
+
+/**
+ * General utilities that are useful in creating custom Event Plugins.
+ */
+var EventPluginUtils = {
+ isEndish: isEndish,
+ isMoveish: isMoveish,
+ isStartish: isStartish,
+ executeDispatchesInOrder: executeDispatchesInOrder,
+ executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
+ executeDirectDispatch: executeDirectDispatch,
+ hasDispatches: hasDispatches,
+ executeDispatch: executeDispatch
+};
+
+module.exports = EventPluginUtils;
+
+},{"./EventConstants":13,"./invariant":78}],18:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventPropagators
+ */
+
+"use strict";
+
+var CallbackRegistry = require("./CallbackRegistry");
+var EventConstants = require("./EventConstants");
+
+var accumulate = require("./accumulate");
+var forEachAccumulated = require("./forEachAccumulated");
+var getListener = CallbackRegistry.getListener;
+var PropagationPhases = EventConstants.PropagationPhases;
+
+/**
+ * Injected dependencies:
+ */
+
+/**
+ * - `InstanceHandle`: [required] Module that performs logical traversals of DOM
+ * hierarchy given ids of the logical DOM elements involved.
+ */
+var injection = {
+ InstanceHandle: null,
+ injectInstanceHandle: function(InjectedInstanceHandle) {
+ injection.InstanceHandle = InjectedInstanceHandle;
+ if (true) {
+ injection.validate();
+ }
+ },
+ validate: function() {
+ var invalid = !injection.InstanceHandle||
+ !injection.InstanceHandle.traverseTwoPhase ||
+ !injection.InstanceHandle.traverseEnterLeave;
+ if (invalid) {
+ throw new Error('InstanceHandle not injected before use!');
+ }
+ }
+};
+
+/**
+ * Some event types have a notion of different registration names for different
+ * "phases" of propagation. This finds listeners by a given phase.
+ */
+function listenerAtPhase(id, event, propagationPhase) {
+ var registrationName =
+ event.dispatchConfig.phasedRegistrationNames[propagationPhase];
+ return getListener(id, registrationName);
+}
+
+/**
+ * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
+ * here, allows us to not have to bind or create functions for each event.
+ * Mutating the event's members allows us to not have to create a wrapping
+ * "dispatch" object that pairs the event with the listener.
+ */
+function accumulateDirectionalDispatches(domID, upwards, event) {
+ if (true) {
+ if (!domID) {
+ throw new Error('Dispatching id must not be null');
+ }
+ injection.validate();
+ }
+ var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
+ var listener = listenerAtPhase(domID, event, phase);
+ if (listener) {
+ event._dispatchListeners = accumulate(event._dispatchListeners, listener);
+ event._dispatchIDs = accumulate(event._dispatchIDs, domID);
+ }
+}
+
+/**
+ * Collect dispatches (must be entirely collected before dispatching - see unit
+ * tests). Lazily allocate the array to conserve memory. We must loop through
+ * each event and perform the traversal for each one. We can not perform a
+ * single traversal for the entire collection of events because each event may
+ * have a different target.
+ */
+function accumulateTwoPhaseDispatchesSingle(event) {
+ if (event && event.dispatchConfig.phasedRegistrationNames) {
+ injection.InstanceHandle.traverseTwoPhase(
+ event.dispatchMarker,
+ accumulateDirectionalDispatches,
+ event
+ );
+ }
+}
+
+
+/**
+ * Accumulates without regard to direction, does not look for phased
+ * registration names. Same as `accumulateDirectDispatchesSingle` but without
+ * requiring that the `dispatchMarker` be the same as the dispatched ID.
+ */
+function accumulateDispatches(id, ignoredDirection, event) {
+ if (event && event.dispatchConfig.registrationName) {
+ var registrationName = event.dispatchConfig.registrationName;
+ var listener = getListener(id, registrationName);
+ if (listener) {
+ event._dispatchListeners = accumulate(event._dispatchListeners, listener);
+ event._dispatchIDs = accumulate(event._dispatchIDs, id);
+ }
+ }
+}
+
+/**
+ * Accumulates dispatches on an `SyntheticEvent`, but only for the
+ * `dispatchMarker`.
+ * @param {SyntheticEvent} event
+ */
+function accumulateDirectDispatchesSingle(event) {
+ if (event && event.dispatchConfig.registrationName) {
+ accumulateDispatches(event.dispatchMarker, null, event);
+ }
+}
+
+function accumulateTwoPhaseDispatches(events) {
+ if (true) {
+ injection.validate();
+ }
+ forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
+}
+
+function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
+ if (true) {
+ injection.validate();
+ }
+ injection.InstanceHandle.traverseEnterLeave(
+ fromID,
+ toID,
+ accumulateDispatches,
+ leave,
+ enter
+ );
+}
+
+
+function accumulateDirectDispatches(events) {
+ if (true) {
+ injection.validate();
+ }
+ forEachAccumulated(events, accumulateDirectDispatchesSingle);
+}
+
+
+
+/**
+ * A small set of propagation patterns, each of which will accept a small amount
+ * of information, and generate a set of "dispatch ready event objects" - which
+ * are sets of events that have already been annotated with a set of dispatched
+ * listener functions/ids. The API is designed this way to discourage these
+ * propagation strategies from actually executing the dispatches, since we
+ * always want to collect the entire set of dispatches before executing event a
+ * single one.
+ *
+ * @constructor EventPropagators
+ */
+var EventPropagators = {
+ accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
+ accumulateDirectDispatches: accumulateDirectDispatches,
+ accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches,
+ injection: injection
+};
+
+module.exports = EventPropagators;
+
+},{"./CallbackRegistry":4,"./EventConstants":13,"./accumulate":61,"./forEachAccumulated":70}],19:[function(require,module,exports){
+(function(){/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ExecutionEnvironment
+ */
+
+/*jslint evil: true */
+
+"use strict";
+
+var canUseDOM = typeof window !== 'undefined';
+
+/**
+ * Simple, lightweight module assisting with the detection and context of
+ * Worker. Helps avoid circular dependencies and allows code to reason about
+ * whether or not they are in a Worker, even if they never include the main
+ * `ReactWorker` dependency.
+ */
+var ExecutionEnvironment = {
+
+ canUseDOM: canUseDOM,
+
+ canUseWorkers: typeof Worker !== 'undefined',
+
+ isInWorker: !canUseDOM, // For now, this is true - might change in the future.
+
+ global: new Function('return this;')()
+
+};
+
+module.exports = ExecutionEnvironment;
+
+})()
+},{}],20:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule MobileSafariClickEventPlugin
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var EventConstants = require("./EventConstants");
+
+var emptyFunction = require("./emptyFunction");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+/**
+ * Mobile Safari does not fire properly bubble click events on non-interactive
+ * elements, which means delegated click listeners do not fire. The workaround
+ * for this bug involves attaching an empty click listener on the target node.
+ *
+ * This particular plugin works around the bug by attaching an empty click
+ * listener on `touchstart` (which does fire on every element).
+ */
+var MobileSafariClickEventPlugin = {
+
+ eventTypes: null,
+
+ /**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {*} An accumulation of synthetic events.
+ * @see {EventPluginHub.extractEvents}
+ */
+ extractEvents: function(
+ topLevelType,
+ topLevelTarget,
+ topLevelTargetID,
+ nativeEvent) {
+ if (topLevelType === topLevelTypes.topTouchStart) {
+ var target = nativeEvent.target;
+ if (target && !target.onclick) {
+ target.onclick = emptyFunction;
+ }
+ }
+ }
+
+};
+
+module.exports = MobileSafariClickEventPlugin;
+
+},{"./EventConstants":13,"./emptyFunction":66}],21:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule PooledClass
+ */
+
+"use strict";
+
+/**
+ * Static poolers. Several custom versions for each potential number of
+ * arguments. A completely generic pooler is easy to implement, but would
+ * require accessing the `arguments` object. In each of these, `this` refers to
+ * the Class itself, not an instance. If any others are needed, simply add them
+ * here, or in their own files.
+ */
+var oneArgumentPooler = function(copyFieldsFrom) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, copyFieldsFrom);
+ return instance;
+ } else {
+ return new Klass(copyFieldsFrom);
+ }
+};
+
+var twoArgumentPooler = function(a1, a2) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2);
+ return instance;
+ } else {
+ return new Klass(a1, a2);
+ }
+};
+
+var threeArgumentPooler = function(a1, a2, a3) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2, a3);
+ return instance;
+ } else {
+ return new Klass(a1, a2, a3);
+ }
+};
+
+var fiveArgumentPooler = function(a1, a2, a3, a4, a5) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2, a3, a4, a5);
+ return instance;
+ } else {
+ return new Klass(a1, a2, a3, a4, a5);
+ }
+};
+
+var standardReleaser = function(instance) {
+ var Klass = this;
+ if (instance.destructor) {
+ instance.destructor();
+ }
+ if (Klass.instancePool.length < Klass.poolSize) {
+ Klass.instancePool.push(instance);
+ }
+};
+
+var DEFAULT_POOL_SIZE = 10;
+var DEFAULT_POOLER = oneArgumentPooler;
+
+/**
+ * Augments `CopyConstructor` to be a poolable class, augmenting only the class
+ * itself (statically) not adding any prototypical fields. Any CopyConstructor
+ * you give this may have a `poolSize` property, and will look for a
+ * prototypical `destructor` on instances (optional).
+ *
+ * @param {Function} CopyConstructor Constructor that can be used to reset.
+ * @param {Function} pooler Customizable pooler.
+ */
+var addPoolingTo = function(CopyConstructor, pooler) {
+ var NewKlass = CopyConstructor;
+ NewKlass.instancePool = [];
+ NewKlass.getPooled = pooler || DEFAULT_POOLER;
+ if (!NewKlass.poolSize) {
+ NewKlass.poolSize = DEFAULT_POOL_SIZE;
+ }
+ NewKlass.release = standardReleaser;
+ return NewKlass;
+};
+
+var PooledClass = {
+ addPoolingTo: addPoolingTo,
+ oneArgumentPooler: oneArgumentPooler,
+ twoArgumentPooler: twoArgumentPooler,
+ threeArgumentPooler: threeArgumentPooler,
+ fiveArgumentPooler: fiveArgumentPooler
+};
+
+module.exports = PooledClass;
+
+},{}],22:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule React
+ */
+
+"use strict";
+
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactComponent = require("./ReactComponent");
+var ReactDOM = require("./ReactDOM");
+var ReactMount = require("./ReactMount");
+var ReactPropTypes = require("./ReactPropTypes");
+var ReactServerRendering = require("./ReactServerRendering");
+
+var ReactDefaultInjection = require("./ReactDefaultInjection");
+
+ReactDefaultInjection.inject();
+
+var React = {
+ DOM: ReactDOM,
+ PropTypes: ReactPropTypes,
+ initializeTouchEvents: function(shouldUseTouch) {
+ ReactMount.useTouchEvents = shouldUseTouch;
+ },
+ autoBind: ReactCompositeComponent.autoBind,
+ createClass: ReactCompositeComponent.createClass,
+ constructAndRenderComponent: ReactMount.constructAndRenderComponent,
+ constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
+ renderComponent: ReactMount.renderComponent,
+ renderComponentToString: ReactServerRendering.renderComponentToString,
+ unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode,
+ isValidComponent: ReactComponent.isValidComponent
+};
+
+module.exports = React;
+
+},{"./ReactComponent":23,"./ReactCompositeComponent":24,"./ReactDOM":26,"./ReactDefaultInjection":33,"./ReactMount":39,"./ReactPropTypes":45,"./ReactServerRendering":47}],23:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ReactComponent
+ */
+
+/*jslint evil: true */
+
+"use strict";
+
+var getReactRootElementInContainer = require("./getReactRootElementInContainer");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactDOMIDOperations = require("./ReactDOMIDOperations");
+var ReactMarkupChecksum = require("./ReactMarkupChecksum");
+var ReactMount = require("./ReactMount");
+var ReactOwner = require("./ReactOwner");
+var ReactReconcileTransaction = require("./ReactReconcileTransaction");
+var ReactUpdates = require("./ReactUpdates");
+
+var invariant = require("./invariant");
+var keyMirror = require("./keyMirror");
+var merge = require("./merge");
+
+/**
+ * Prop key that references a component's owner.
+ * @private
+ */
+var OWNER = '{owner}';
+
+/**
+ * Props key that determines if a component's key was already validated.
+ * @private
+ */
+var IS_KEY_VALIDATED = '{is.key.validated}';
+
+/**
+ * Every React component is in one of these life cycles.
+ */
+var ComponentLifeCycle = keyMirror({
+ /**
+ * Mounted components have a DOM node representation and are capable of
+ * receiving new props.
+ */
+ MOUNTED: null,
+ /**
+ * Unmounted components are inactive and cannot receive new props.
+ */
+ UNMOUNTED: null
+});
+
+/**
+ * Warn if there's no key explicitly set on dynamic arrays of children.
+ * This allows us to keep track of children between updates.
+ */
+
+var ownerHasWarned = {};
+
+/**
+ * Warn if the component doesn't have an explicit key assigned to it.
+ * This component is in an array. The array could grow and shrink or be
+ * reordered. All children, that hasn't already been validated, are required to
+ * have a "key" property assigned to it.
+ *
+ * @internal
+ * @param {ReactComponent} component Component that requires a key.
+ */
+function validateExplicitKey(component) {
+ if (component[IS_KEY_VALIDATED] || component.props.key != null) {
+ return;
+ }
+ component[IS_KEY_VALIDATED] = true;
+
+ // We can't provide friendly warnings for top level components.
+ if (!ReactCurrentOwner.current) {
+ return;
+ }
+
+ // Name of the component whose render method tried to pass children.
+ var currentName = ReactCurrentOwner.current.constructor.displayName;
+ if (ownerHasWarned.hasOwnProperty(currentName)) {
+ return;
+ }
+ ownerHasWarned[currentName] = true;
+
+ var message = 'Each child in an array should have a unique "key" prop. ' +
+ 'Check the render method of ' + currentName + '.';
+ if (!component.isOwnedBy(ReactCurrentOwner.current)) {
+ // Name of the component that originally created this child.
+ var childOwnerName =
+ component.props[OWNER] && component.props[OWNER].constructor.displayName;
+
+ // Usually the current owner is the offender, but if it accepts
+ // children as a property, it may be the creator of the child that's
+ // responsible for assigning it a key.
+ message += ' It was passed a child from ' + childOwnerName + '.';
+ }
+
+ console.warn(message);
+}
+
+/**
+ * Ensure that every component either is passed in a static location or, if
+ * if it's passed in an array, has an explicit key property defined.
+ *
+ * @internal
+ * @param {*} component Statically passed child of any type.
+ * @return {boolean}
+ */
+function validateChildKeys(component) {
+ if (Array.isArray(component)) {
+ for (var i = 0; i < component.length; i++) {
+ var child = component[i];
+ if (ReactComponent.isValidComponent(child)) {
+ validateExplicitKey(child);
+ }
+ }
+ } else if (ReactComponent.isValidComponent(component)) {
+ // This component was passed in a valid location.
+ component[IS_KEY_VALIDATED] = true;
+ }
+}
+
+/**
+ * Components are the basic units of composition in React.
+ *
+ * Every component accepts a set of keyed input parameters known as "props" that
+ * are initialized by the constructor. Once a component is mounted, the props
+ * can be mutated using `setProps` or `replaceProps`.
+ *
+ * Every component is capable of the following operations:
+ *
+ * `mountComponent`
+ * Initializes the component, renders markup, and registers event listeners.
+ *
+ * `receiveProps`
+ * Updates the rendered DOM nodes given a new set of props.
+ *
+ * `unmountComponent`
+ * Releases any resources allocated by this component.
+ *
+ * Components can also be "owned" by other components. Being owned by another
+ * component means being constructed by that component. This is different from
+ * being the child of a component, which means having a DOM representation that
+ * is a child of the DOM representation of that component.
+ *
+ * @class ReactComponent
+ */
+var ReactComponent = {
+
+ /**
+ * @param {?object} object
+ * @return {boolean} True if `object` is a valid component.
+ * @final
+ */
+ isValidComponent: function(object) {
+ return !!(
+ object &&
+ typeof object.mountComponentIntoNode === 'function' &&
+ typeof object.receiveProps === 'function'
+ );
+ },
+
+ /**
+ * Generate a key string that identifies a component within a set.
+ *
+ * @param {*} component A component that could contain a manual key.
+ * @param {number} index Index that is used if a manual key is not provided.
+ * @return {string}
+ * @internal
+ */
+ getKey: function(component, index) {
+ if (component && component.props && component.props.key != null) {
+ // Explicit key
+ return '' + component.props.key;
+ }
+ // Implicit key determined by the index in the set
+ return '' + index;
+ },
+
+ /**
+ * @internal
+ */
+ LifeCycle: ComponentLifeCycle,
+
+ /**
+ * React references `ReactDOMIDOperations` using this property in order to
+ * allow dependency injection.
+ *
+ * @internal
+ */
+ DOMIDOperations: ReactDOMIDOperations,
+
+ /**
+ * React references `ReactReconcileTransaction` using this property in order
+ * to allow dependency injection.
+ *
+ * @internal
+ */
+ ReactReconcileTransaction: ReactReconcileTransaction,
+
+ /**
+ * @param {object} DOMIDOperations
+ * @final
+ */
+ setDOMOperations: function(DOMIDOperations) {
+ ReactComponent.DOMIDOperations = DOMIDOperations;
+ },
+
+ /**
+ * @param {Transaction} ReactReconcileTransaction
+ * @final
+ */
+ setReactReconcileTransaction: function(ReactReconcileTransaction) {
+ ReactComponent.ReactReconcileTransaction = ReactReconcileTransaction;
+ },
+
+ /**
+ * Base functionality for every ReactComponent constructor.
+ *
+ * @lends {ReactComponent.prototype}
+ */
+ Mixin: {
+
+ /**
+ * Checks whether or not this component is mounted.
+ *
+ * @return {boolean} True if mounted, false otherwise.
+ * @final
+ * @protected
+ */
+ isMounted: function() {
+ return this._lifeCycleState === ComponentLifeCycle.MOUNTED;
+ },
+
+ /**
+ * Returns the DOM node rendered by this component.
+ *
+ * @return {DOMElement} The root node of this component.
+ * @final
+ * @protected
+ */
+ getDOMNode: function() {
+ invariant(
+ this.isMounted(),
+ 'getDOMNode(): A component must be mounted to have a DOM node.'
+ );
+ return ReactMount.getNode(this._rootNodeID);
+ },
+
+ /**
+ * Sets a subset of the props.
+ *
+ * @param {object} partialProps Subset of the next props.
+ * @param {?function} callback Called after props are updated.
+ * @final
+ * @public
+ */
+ setProps: function(partialProps, callback) {
+ // Merge with `_pendingProps` if it exists, otherwise with existing props.
+ this.replaceProps(
+ merge(this._pendingProps || this.props, partialProps),
+ callback
+ );
+ },
+
+ /**
+ * Replaces all of the props.
+ *
+ * @param {object} props New props.
+ * @param {?function} callback Called after props are updated.
+ * @final
+ * @public
+ */
+ replaceProps: function(props, callback) {
+ invariant(
+ !this.props[OWNER],
+ 'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
+ 'component with an owner. This is an anti-pattern since props will ' +
+ 'get reactively updated when rendered. Instead, change the owner\'s ' +
+ '`render` method to pass the correct value as props to the component ' +
+ 'where it is created.'
+ );
+ this._pendingProps = props;
+ ReactUpdates.enqueueUpdate(this, callback);
+ },
+
+ /**
+ * Base constructor for all React component.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.construct.call(this, ...)`.
+ *
+ * @param {?object} initialProps
+ * @param {*} children
+ * @internal
+ */
+ construct: function(initialProps, children) {
+ this.props = initialProps || {};
+ // Record the component responsible for creating this component.
+ this.props[OWNER] = ReactCurrentOwner.current;
+ // All components start unmounted.
+ this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
+
+ this._pendingProps = null;
+ this._pendingCallbacks = null;
+
+ // Children can be more than one argument
+ var childrenLength = arguments.length - 1;
+ if (childrenLength === 1) {
+ if (true) {
+ validateChildKeys(children);
+ }
+ this.props.children = children;
+ } else if (childrenLength > 1) {
+ var childArray = Array(childrenLength);
+ for (var i = 0; i < childrenLength; i++) {
+ if (true) {
+ validateChildKeys(arguments[i + 1]);
+ }
+ childArray[i] = arguments[i + 1];
+ }
+ this.props.children = childArray;
+ }
+ },
+
+ /**
+ * Initializes the component, renders markup, and registers event listeners.
+ *
+ * NOTE: This does not insert any nodes into the DOM.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.mountComponent.call(this, ...)`.
+ *
+ * @param {string} rootID DOM ID of the root node.
+ * @param {ReactReconcileTransaction} transaction
+ * @return {?string} Rendered markup to be inserted into the DOM.
+ * @internal
+ */
+ mountComponent: function(rootID, transaction) {
+ invariant(
+ !this.isMounted(),
+ 'mountComponent(%s, ...): Can only mount an unmounted component.',
+ rootID
+ );
+ var props = this.props;
+ if (props.ref != null) {
+ ReactOwner.addComponentAsRefTo(this, props.ref, props[OWNER]);
+ }
+ this._rootNodeID = rootID;
+ this._lifeCycleState = ComponentLifeCycle.MOUNTED;
+ // Effectively: return '';
+ },
+
+ /**
+ * Releases any resources allocated by `mountComponent`.
+ *
+ * NOTE: This does not remove any nodes from the DOM.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.unmountComponent.call(this)`.
+ *
+ * @internal
+ */
+ unmountComponent: function() {
+ invariant(
+ this.isMounted(),
+ 'unmountComponent(): Can only unmount a mounted component.'
+ );
+ var props = this.props;
+ if (props.ref != null) {
+ ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]);
+ }
+ ReactMount.purgeID(this._rootNodeID);
+ this._rootNodeID = null;
+ this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
+ },
+
+ /**
+ * Updates the rendered DOM nodes given a new set of props.
+ *
+ * Subclasses that override this method should make sure to invoke
+ * `ReactComponent.Mixin.receiveProps.call(this, ...)`.
+ *
+ * @param {object} nextProps Next set of properties.
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ receiveProps: function(nextProps, transaction) {
+ invariant(
+ this.isMounted(),
+ 'receiveProps(...): Can only update a mounted component.'
+ );
+ this._pendingProps = nextProps;
+ this._performUpdateIfNecessary(transaction);
+ },
+
+ /**
+ * Call `_performUpdateIfNecessary` within a new transaction.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ performUpdateIfNecessary: function() {
+ var transaction = ReactComponent.ReactReconcileTransaction.getPooled();
+ transaction.perform(this._performUpdateIfNecessary, this, transaction);
+ ReactComponent.ReactReconcileTransaction.release(transaction);
+ },
+
+ /**
+ * If `_pendingProps` is set, update the component.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ _performUpdateIfNecessary: function(transaction) {
+ if (this._pendingProps == null) {
+ return;
+ }
+ var prevProps = this.props;
+ this.props = this._pendingProps;
+ this._pendingProps = null;
+ this.updateComponent(transaction, prevProps);
+ },
+
+ /**
+ * Updates the component's currently mounted representation.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @param {object} prevProps
+ * @internal
+ */
+ updateComponent: function(transaction, prevProps) {
+ var props = this.props;
+ // If either the owner or a `ref` has changed, make sure the newest owner
+ // has stored a reference to `this`, and the previous owner (if different)
+ // has forgotten the reference to `this`.
+ if (props[OWNER] !== prevProps[OWNER] || props.ref !== prevProps.ref) {
+ if (prevProps.ref != null) {
+ ReactOwner.removeComponentAsRefFrom(
+ this, prevProps.ref, prevProps[OWNER]
+ );
+ }
+ // Correct, even if the owner is the same, and only the ref has changed.
+ if (props.ref != null) {
+ ReactOwner.addComponentAsRefTo(this, props.ref, props[OWNER]);
+ }
+ }
+ },
+
+ /**
+ * Mounts this component and inserts it into the DOM.
+ *
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ * @final
+ * @internal
+ * @see {ReactMount.renderComponent}
+ */
+ mountComponentIntoNode: function(rootID, container, shouldReuseMarkup) {
+ var transaction = ReactComponent.ReactReconcileTransaction.getPooled();
+ transaction.perform(
+ this._mountComponentIntoNode,
+ this,
+ rootID,
+ container,
+ transaction,
+ shouldReuseMarkup
+ );
+ ReactComponent.ReactReconcileTransaction.release(transaction);
+ },
+
+ /**
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {ReactReconcileTransaction} transaction
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ * @final
+ * @private
+ */
+ _mountComponentIntoNode: function(
+ rootID,
+ container,
+ transaction,
+ shouldReuseMarkup) {
+ invariant(
+ container && container.nodeType === 1,
+ 'mountComponentIntoNode(...): Target container is not a DOM element.'
+ );
+ var markup = this.mountComponent(rootID, transaction);
+
+ if (shouldReuseMarkup) {
+ if (ReactMarkupChecksum.canReuseMarkup(
+ markup,
+ getReactRootElementInContainer(container))) {
+ return;
+ } else {
+ if (true) {
+ console.warn(
+ 'React attempted to use reuse markup in a container but the ' +
+ 'checksum was invalid. This generally means that you are using ' +
+ 'server rendering and the markup generated on the server was ' +
+ 'not what the client was expecting. React injected new markup ' +
+ 'to compensate which works but you have lost many of the ' +
+ 'benefits of server rendering. Instead, figure out why the ' +
+ 'markup being generated is different on the client or server.'
+ );
+ }
+ }
+ }
+
+ // Asynchronously inject markup by ensuring that the container is not in
+ // the document when settings its `innerHTML`.
+ var parent = container.parentNode;
+ if (parent) {
+ var next = container.nextSibling;
+ parent.removeChild(container);
+ container.innerHTML = markup;
+ if (next) {
+ parent.insertBefore(container, next);
+ } else {
+ parent.appendChild(container);
+ }
+ } else {
+ container.innerHTML = markup;
+ }
+ },
+
+ /**
+ * Unmounts this component and removes it from the DOM.
+ *
+ * @param {DOMElement} container DOM element to unmount from.
+ * @final
+ * @internal
+ * @see {ReactMount.unmountAndReleaseReactRootNode}
+ */
+ unmountComponentFromNode: function(container) {
+ this.unmountComponent();
+ // http://jsperf.com/emptying-a-node
+ while (container.lastChild) {
+ container.removeChild(container.lastChild);
+ }
+ },
+
+ /**
+ * Checks if this component is owned by the supplied `owner` component.
+ *
+ * @param {ReactComponent} owner Component to check.
+ * @return {boolean} True if `owners` owns this component.
+ * @final
+ * @internal
+ */
+ isOwnedBy: function(owner) {
+ return this.props[OWNER] === owner;
+ },
+
+ /**
+ * Gets another component, that shares the same owner as this one, by ref.
+ *
+ * @param {string} ref of a sibling Component.
+ * @return {?ReactComponent} the actual sibling Component.
+ * @final
+ * @internal
+ */
+ getSiblingByRef: function(ref) {
+ var owner = this.props[OWNER];
+ if (!owner || !owner.refs) {
+ return null;
+ }
+ return owner.refs[ref];
+ }
+
+ }
+
+};
+
+module.exports = ReactComponent;
+
+},{"./ReactCurrentOwner":25,"./ReactDOMIDOperations":28,"./ReactMarkupChecksum":38,"./ReactMount":39,"./ReactOwner":43,"./ReactReconcileTransaction":46,"./ReactUpdates":49,"./getReactRootElementInContainer":73,"./invariant":78,"./keyMirror":81,"./merge":84}],24:[function(require,module,exports){
+(function(){/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ReactCompositeComponent
+ */
+
+"use strict";
+
+var ReactComponent = require("./ReactComponent");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactOwner = require("./ReactOwner");
+var ReactPropTransferer = require("./ReactPropTransferer");
+var ReactUpdates = require("./ReactUpdates");
+
+var invariant = require("./invariant");
+var keyMirror = require("./keyMirror");
+var merge = require("./merge");
+var mixInto = require("./mixInto");
+
+/**
+ * Policies that describe methods in `ReactCompositeComponentInterface`.
+ */
+var SpecPolicy = keyMirror({
+ /**
+ * These methods may be defined only once by the class specification or mixin.
+ */
+ DEFINE_ONCE: null,
+ /**
+ * These methods may be defined by both the class specification and mixins.
+ * Subsequent definitions will be chained. These methods must return void.
+ */
+ DEFINE_MANY: null,
+ /**
+ * These methods are overriding the base ReactCompositeComponent class.
+ */
+ OVERRIDE_BASE: null
+});
+
+/**
+ * Composite components are higher-level components that compose other composite
+ * or native components.
+ *
+ * To create a new type of `ReactCompositeComponent`, pass a specification of
+ * your new class to `React.createClass`. The only requirement of your class
+ * specification is that you implement a `render` method.
+ *
+ * var MyComponent = React.createClass({
+ * render: function() {
+ * return
Hello World
;
+ * }
+ * });
+ *
+ * The class specification supports a specific protocol of methods that have
+ * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
+ * more the comprehensive protocol. Any other properties and methods in the
+ * class specification will available on the prototype.
+ *
+ * @interface ReactCompositeComponentInterface
+ * @internal
+ */
+var ReactCompositeComponentInterface = {
+
+ /**
+ * An array of Mixin objects to include when defining your component.
+ *
+ * @type {array}
+ * @optional
+ */
+ mixins: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Definition of prop types for this component.
+ *
+ * @type {object}
+ * @optional
+ */
+ propTypes: SpecPolicy.DEFINE_ONCE,
+
+
+
+ // ==== Definition methods ====
+
+ /**
+ * Invoked when the component is mounted. Values in the mapping will be set on
+ * `this.props` if that prop is not specified (i.e. using an `in` check).
+ *
+ * This method is invoked before `getInitialState` and therefore cannot rely
+ * on `this.state` or use `this.setState`.
+ *
+ * @return {object}
+ * @optional
+ */
+ getDefaultProps: SpecPolicy.DEFINE_ONCE,
+
+ /**
+ * Invoked once before the component is mounted. The return value will be used
+ * as the initial value of `this.state`.
+ *
+ * getInitialState: function() {
+ * return {
+ * isOn: false,
+ * fooBaz: new BazFoo()
+ * }
+ * }
+ *
+ * @return {object}
+ * @optional
+ */
+ getInitialState: SpecPolicy.DEFINE_ONCE,
+
+ /**
+ * Uses props from `this.props` and state from `this.state` to render the
+ * structure of the component.
+ *
+ * No guarantees are made about when or how often this method is invoked, so
+ * it must not have side effects.
+ *
+ * render: function() {
+ * var name = this.props.name;
+ * return
Hello, {name}!
;
+ * }
+ *
+ * @return {ReactComponent}
+ * @nosideeffects
+ * @required
+ */
+ render: SpecPolicy.DEFINE_ONCE,
+
+
+
+ // ==== Delegate methods ====
+
+ /**
+ * Invoked when the component is initially created and about to be mounted.
+ * This may have side effects, but any external subscriptions or data created
+ * by this method must be cleaned up in `componentWillUnmount`.
+ *
+ * @optional
+ */
+ componentWillMount: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked when the component has been mounted and has a DOM representation.
+ * However, there is no guarantee that the DOM node is in the document.
+ *
+ * Use this as an opportunity to operate on the DOM when the component has
+ * been mounted (initialized and rendered) for the first time.
+ *
+ * @param {DOMElement} rootNode DOM element representing the component.
+ * @optional
+ */
+ componentDidMount: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked before the component receives new props.
+ *
+ * Use this as an opportunity to react to a prop transition by updating the
+ * state using `this.setState`. Current props are accessed via `this.props`.
+ *
+ * componentWillReceiveProps: function(nextProps) {
+ * this.setState({
+ * likesIncreasing: nextProps.likeCount > this.props.likeCount
+ * });
+ * }
+ *
+ * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
+ * transition may cause a state change, but the opposite is not true. If you
+ * need it, you are probably looking for `componentWillUpdate`.
+ *
+ * @param {object} nextProps
+ * @optional
+ */
+ componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked while deciding if the component should be updated as a result of
+ * receiving new props and state.
+ *
+ * Use this as an opportunity to `return false` when you're certain that the
+ * transition to the new props and state will not require a component update.
+ *
+ * shouldComponentUpdate: function(nextProps, nextState) {
+ * return !equal(nextProps, this.props) || !equal(nextState, this.state);
+ * }
+ *
+ * @param {object} nextProps
+ * @param {?object} nextState
+ * @return {boolean} True if the component should update.
+ * @optional
+ */
+ shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
+
+ /**
+ * Invoked when the component is about to update due to a transition from
+ * `this.props` and `this.state` to `nextProps` and `nextState`.
+ *
+ * Use this as an opportunity to perform preparation before an update occurs.
+ *
+ * NOTE: You **cannot** use `this.setState()` in this method.
+ *
+ * @param {object} nextProps
+ * @param {?object} nextState
+ * @param {ReactReconcileTransaction} transaction
+ * @optional
+ */
+ componentWillUpdate: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked when the component's DOM representation has been updated.
+ *
+ * Use this as an opportunity to operate on the DOM when the component has
+ * been updated.
+ *
+ * @param {object} prevProps
+ * @param {?object} prevState
+ * @param {DOMElement} rootNode DOM element representing the component.
+ * @optional
+ */
+ componentDidUpdate: SpecPolicy.DEFINE_MANY,
+
+ /**
+ * Invoked when the component is about to be removed from its parent and have
+ * its DOM representation destroyed.
+ *
+ * Use this as an opportunity to deallocate any external resources.
+ *
+ * NOTE: There is no `componentDidUnmount` since your component will have been
+ * destroyed by that point.
+ *
+ * @optional
+ */
+ componentWillUnmount: SpecPolicy.DEFINE_MANY,
+
+
+
+ // ==== Advanced methods ====
+
+ /**
+ * Updates the component's currently mounted DOM representation.
+ *
+ * By default, this implements React's rendering and reconciliation algorithm.
+ * Sophisticated clients may wish to override this.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ * @overridable
+ */
+ updateComponent: SpecPolicy.OVERRIDE_BASE
+
+};
+
+/**
+ * Mapping from class specification keys to special processing functions.
+ *
+ * Although these are declared in the specification when defining classes
+ * using `React.createClass`, they will not be on the component's prototype.
+ */
+var RESERVED_SPEC_KEYS = {
+ displayName: function(Constructor, displayName) {
+ Constructor.displayName = displayName;
+ },
+ mixins: function(Constructor, mixins) {
+ if (mixins) {
+ for (var i = 0; i < mixins.length; i++) {
+ mixSpecIntoComponent(Constructor, mixins[i]);
+ }
+ }
+ },
+ propTypes: function(Constructor, propTypes) {
+ Constructor.propTypes = propTypes;
+ }
+};
+
+function validateMethodOverride(proto, name) {
+ var specPolicy = ReactCompositeComponentInterface[name];
+
+ // Disallow overriding of base class methods unless explicitly allowed.
+ if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
+ invariant(
+ specPolicy === SpecPolicy.OVERRIDE_BASE,
+ 'ReactCompositeComponentInterface: You are attempting to override ' +
+ '`%s` from your class specification. Ensure that your method names ' +
+ 'do not overlap with React methods.',
+ name
+ );
+ }
+
+ // Disallow defining methods more than once unless explicitly allowed.
+ if (proto.hasOwnProperty(name)) {
+ invariant(
+ specPolicy === SpecPolicy.DEFINE_MANY,
+ 'ReactCompositeComponentInterface: You are attempting to define ' +
+ '`%s` on your component more than once. This conflict may be due ' +
+ 'to a mixin.',
+ name
+ );
+ }
+}
+
+
+function validateLifeCycleOnReplaceState(instance) {
+ var compositeLifeCycleState = instance._compositeLifeCycleState;
+ invariant(
+ instance.isMounted() ||
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
+ 'replaceState(...): Can only update a mounted or mounting component.'
+ );
+ invariant(
+ compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
+ compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
+ 'replaceState(...): Cannot update while unmounting component or during ' +
+ 'an existing state transition (such as within `render`).'
+ );
+}
+
+/**
+ * Custom version of `mixInto` which handles policy validation and reserved
+ * specification keys when building `ReactCompositeComponent` classses.
+ */
+function mixSpecIntoComponent(Constructor, spec) {
+ var proto = Constructor.prototype;
+ for (var name in spec) {
+ var property = spec[name];
+ if (!spec.hasOwnProperty(name) || !property) {
+ continue;
+ }
+ validateMethodOverride(proto, name);
+
+ if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
+ RESERVED_SPEC_KEYS[name](Constructor, property);
+ } else {
+ // Setup methods on prototype:
+ // The following member methods should not be automatically bound:
+ // 1. Expected ReactCompositeComponent methods (in the "interface").
+ // 2. Overridden methods (that were mixed in).
+ var isCompositeComponentMethod = name in ReactCompositeComponentInterface;
+ var isInherited = name in proto;
+ var markedDontBind = property.__reactDontBind;
+ var isFunction = typeof property === 'function';
+ var shouldAutoBind =
+ isFunction &&
+ !isCompositeComponentMethod &&
+ !isInherited &&
+ !markedDontBind;
+
+ if (shouldAutoBind) {
+ if (!proto.__reactAutoBindMap) {
+ proto.__reactAutoBindMap = {};
+ }
+ proto.__reactAutoBindMap[name] = property;
+ proto[name] = property;
+ } else {
+ if (isInherited) {
+ // For methods which are defined more than once, call the existing
+ // methods before calling the new property.
+ proto[name] = createChainedFunction(proto[name], property);
+ } else {
+ proto[name] = property;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Creates a function that invokes two functions and ignores their return vales.
+ *
+ * @param {function} one Function to invoke first.
+ * @param {function} two Function to invoke second.
+ * @return {function} Function that invokes the two argument functions.
+ * @private
+ */
+function createChainedFunction(one, two) {
+ return function chainedFunction() {
+ one.apply(this, arguments);
+ two.apply(this, arguments);
+ };
+}
+
+/**
+ * `ReactCompositeComponent` maintains an auxiliary life cycle state in
+ * `this._compositeLifeCycleState` (which can be null).
+ *
+ * This is different from the life cycle state maintained by `ReactComponent` in
+ * `this._lifeCycleState`. The following diagram shows how the states overlap in
+ * time. There are times when the CompositeLifeCycle is null - at those times it
+ * is only meaningful to look at ComponentLifeCycle alone.
+ *
+ * Top Row: ReactComponent.ComponentLifeCycle
+ * Low Row: ReactComponent.CompositeLifeCycle
+ *
+ * +-------+------------------------------------------------------+--------+
+ * | UN | MOUNTED | UN |
+ * |MOUNTED| | MOUNTED|
+ * +-------+------------------------------------------------------+--------+
+ * | ^--------+ +------+ +------+ +------+ +--------^ |
+ * | | | | | | | | | | | |
+ * | 0--|MOUNTING|-0-|RECEIV|-0-|RECEIV|-0-|RECEIV|-0-| UN |--->0 |
+ * | | | |PROPS | | PROPS| | STATE| |MOUNTING| |
+ * | | | | | | | | | | | |
+ * | | | | | | | | | | | |
+ * | +--------+ +------+ +------+ +------+ +--------+ |
+ * | | | |
+ * +-------+------------------------------------------------------+--------+
+ */
+var CompositeLifeCycle = keyMirror({
+ /**
+ * Components in the process of being mounted respond to state changes
+ * differently.
+ */
+ MOUNTING: null,
+ /**
+ * Components in the process of being unmounted are guarded against state
+ * changes.
+ */
+ UNMOUNTING: null,
+ /**
+ * Components that are mounted and receiving new props respond to state
+ * changes differently.
+ */
+ RECEIVING_PROPS: null,
+ /**
+ * Components that are mounted and receiving new state are guarded against
+ * additional state changes.
+ */
+ RECEIVING_STATE: null
+});
+
+/**
+ * @lends {ReactCompositeComponent.prototype}
+ */
+var ReactCompositeComponentMixin = {
+
+ /**
+ * Base constructor for all composite component.
+ *
+ * @param {?object} initialProps
+ * @param {*} children
+ * @final
+ * @internal
+ */
+ construct: function(initialProps, children) {
+ // Children can be either an array or more than one argument
+ ReactComponent.Mixin.construct.apply(this, arguments);
+ this.state = null;
+ this._pendingState = null;
+ this._compositeLifeCycleState = null;
+ },
+
+ /**
+ * Checks whether or not this composite component is mounted.
+ * @return {boolean} True if mounted, false otherwise.
+ * @protected
+ * @final
+ */
+ isMounted: function() {
+ return ReactComponent.Mixin.isMounted.call(this) &&
+ this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
+ },
+
+ /**
+ * Initializes the component, renders markup, and registers event listeners.
+ *
+ * @param {string} rootID DOM ID of the root node.
+ * @param {ReactReconcileTransaction} transaction
+ * @return {?string} Rendered markup to be inserted into the DOM.
+ * @final
+ * @internal
+ */
+ mountComponent: function(rootID, transaction) {
+ ReactComponent.Mixin.mountComponent.call(this, rootID, transaction);
+ this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
+
+ this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
+ this._processProps(this.props);
+
+ if (this.__reactAutoBindMap) {
+ this._bindAutoBindMethods();
+ }
+
+ this.state = this.getInitialState ? this.getInitialState() : null;
+ this._pendingState = null;
+ this._pendingForceUpdate = false;
+
+ if (this.componentWillMount) {
+ this.componentWillMount();
+ // When mounting, calls to `setState` by `componentWillMount` will set
+ // `this._pendingState` without triggering a re-render.
+ if (this._pendingState) {
+ this.state = this._pendingState;
+ this._pendingState = null;
+ }
+ }
+
+ this._renderedComponent = this._renderValidatedComponent();
+
+ // Done with mounting, `setState` will now trigger UI changes.
+ this._compositeLifeCycleState = null;
+ var markup = this._renderedComponent.mountComponent(rootID, transaction);
+ if (this.componentDidMount) {
+ transaction.getReactOnDOMReady().enqueue(this, this.componentDidMount);
+ }
+ return markup;
+ },
+
+ /**
+ * Releases any resources allocated by `mountComponent`.
+ *
+ * @final
+ * @internal
+ */
+ unmountComponent: function() {
+ this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
+ if (this.componentWillUnmount) {
+ this.componentWillUnmount();
+ }
+ this._compositeLifeCycleState = null;
+
+ this._defaultProps = null;
+
+ ReactComponent.Mixin.unmountComponent.call(this);
+ this._renderedComponent.unmountComponent();
+ this._renderedComponent = null;
+
+ if (this.refs) {
+ this.refs = null;
+ }
+
+ // Some existing components rely on this.props even after they've been
+ // destroyed (in event handlers).
+ // TODO: this.props = null;
+ // TODO: this.state = null;
+ },
+
+ /**
+ * Sets a subset of the state. Always use this or `replaceState` to mutate
+ * state. You should treat `this.state` as immutable.
+ *
+ * There is no guarantee that `this.state` will be immediately updated, so
+ * accessing `this.state` after calling this method may return the old value.
+ *
+ * There is no guarantee that calls to `setState` will run synchronously,
+ * as they may eventually be batched together. You can provide an optional
+ * callback that will be executed when the call to setState is actually
+ * completed.
+ *
+ * @param {object} partialState Next partial state to be merged with state.
+ * @param {?function} callback Called after state is updated.
+ * @final
+ * @protected
+ */
+ setState: function(partialState, callback) {
+ // Merge with `_pendingState` if it exists, otherwise with existing state.
+ this.replaceState(
+ merge(this._pendingState || this.state, partialState),
+ callback
+ );
+ },
+
+ /**
+ * Replaces all of the state. Always use this or `setState` to mutate state.
+ * You should treat `this.state` as immutable.
+ *
+ * There is no guarantee that `this.state` will be immediately updated, so
+ * accessing `this.state` after calling this method may return the old value.
+ *
+ * @param {object} completeState Next state.
+ * @param {?function} callback Called after state is updated.
+ * @final
+ * @protected
+ */
+ replaceState: function(completeState, callback) {
+ validateLifeCycleOnReplaceState(this);
+ this._pendingState = completeState;
+ ReactUpdates.enqueueUpdate(this, callback);
+ },
+
+ /**
+ * Processes props by setting default values for unspecified props and
+ * asserting that the props are valid.
+ *
+ * @param {object} props
+ * @private
+ */
+ _processProps: function(props) {
+ var propName;
+ var defaultProps = this._defaultProps;
+ for (propName in defaultProps) {
+ if (!(propName in props)) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+ var propTypes = this.constructor.propTypes;
+ if (propTypes) {
+ var componentName = this.constructor.displayName;
+ for (propName in propTypes) {
+ var checkProp = propTypes[propName];
+ if (checkProp) {
+ checkProp(props, propName, componentName);
+ }
+ }
+ }
+ },
+
+ performUpdateIfNecessary: function() {
+ var compositeLifeCycleState = this._compositeLifeCycleState;
+ // Do not trigger a state transition if we are in the middle of mounting or
+ // receiving props because both of those will already be doing this.
+ if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
+ compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
+ return;
+ }
+ ReactComponent.Mixin.performUpdateIfNecessary.call(this);
+ },
+
+ /**
+ * If any of `_pendingProps`, `_pendingState`, or `_pendingForceUpdate` is
+ * set, update the component.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @internal
+ */
+ _performUpdateIfNecessary: function(transaction) {
+ if (this._pendingProps == null &&
+ this._pendingState == null &&
+ !this._pendingForceUpdate) {
+ return;
+ }
+
+ var nextProps = this.props;
+ if (this._pendingProps != null) {
+ nextProps = this._pendingProps;
+ this._processProps(nextProps);
+ this._pendingProps = null;
+
+ this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
+ if (this.componentWillReceiveProps) {
+ this.componentWillReceiveProps(nextProps, transaction);
+ }
+ }
+
+ this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE;
+
+ var nextState = this._pendingState || this.state;
+ this._pendingState = null;
+
+ if (this._pendingForceUpdate ||
+ !this.shouldComponentUpdate ||
+ this.shouldComponentUpdate(nextProps, nextState)) {
+ this._pendingForceUpdate = false;
+ // Will set `this.props` and `this.state`.
+ this._performComponentUpdate(nextProps, nextState, transaction);
+ } else {
+ // If it's determined that a component should not update, we still want
+ // to set props and state.
+ this.props = nextProps;
+ this.state = nextState;
+ }
+
+ this._compositeLifeCycleState = null;
+ },
+
+ /**
+ * Merges new props and state, notifies delegate methods of update and
+ * performs update.
+ *
+ * @param {object} nextProps Next object to set as properties.
+ * @param {?object} nextState Next object to set as state.
+ * @param {ReactReconcileTransaction} transaction
+ * @private
+ */
+ _performComponentUpdate: function(nextProps, nextState, transaction) {
+ var prevProps = this.props;
+ var prevState = this.state;
+
+ if (this.componentWillUpdate) {
+ this.componentWillUpdate(nextProps, nextState, transaction);
+ }
+
+ this.props = nextProps;
+ this.state = nextState;
+
+ this.updateComponent(transaction, prevProps, prevState);
+
+ if (this.componentDidUpdate) {
+ transaction.getReactOnDOMReady().enqueue(
+ this,
+ this.componentDidUpdate.bind(this, prevProps, prevState)
+ );
+ }
+ },
+
+ /**
+ * Updates the component's currently mounted DOM representation.
+ *
+ * By default, this implements React's rendering and reconciliation algorithm.
+ * Sophisticated clients may wish to override this.
+ *
+ * @param {ReactReconcileTransaction} transaction
+ * @param {object} prevProps
+ * @param {?object} prevState
+ * @internal
+ * @overridable
+ */
+ updateComponent: function(transaction, prevProps, prevState) {
+ ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps);
+ var currentComponent = this._renderedComponent;
+ var nextComponent = this._renderValidatedComponent();
+ if (currentComponent.constructor === nextComponent.constructor) {
+ currentComponent.receiveProps(nextComponent.props, transaction);
+ } else {
+ // These two IDs are actually the same! But nothing should rely on that.
+ var thisID = this._rootNodeID;
+ var currentComponentID = currentComponent._rootNodeID;
+ currentComponent.unmountComponent();
+ var nextMarkup = nextComponent.mountComponent(thisID, transaction);
+ ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID(
+ currentComponentID,
+ nextMarkup
+ );
+ this._renderedComponent = nextComponent;
+ }
+ },
+
+ /**
+ * Forces an update. This should only be invoked when it is known with
+ * certainty that we are **not** in a DOM transaction.
+ *
+ * You may want to call this when you know that some deeper aspect of the
+ * component's state has changed but `setState` was not called.
+ *
+ * This will not invoke `shouldUpdateComponent`, but it will invoke
+ * `componentWillUpdate` and `componentDidUpdate`.
+ *
+ * @param {?function} callback Called after update is complete.
+ * @final
+ * @protected
+ */
+ forceUpdate: function(callback) {
+ var compositeLifeCycleState = this._compositeLifeCycleState;
+ invariant(
+ this.isMounted() ||
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
+ 'forceUpdate(...): Can only force an update on mounted or mounting ' +
+ 'components.'
+ );
+ invariant(
+ compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
+ compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
+ 'forceUpdate(...): Cannot force an update while unmounting component ' +
+ 'or during an existing state transition (such as within `render`).'
+ );
+ this._pendingForceUpdate = true;
+ ReactUpdates.enqueueUpdate(this, callback);
+ },
+
+ /**
+ * @private
+ */
+ _renderValidatedComponent: function() {
+ var renderedComponent;
+ ReactCurrentOwner.current = this;
+ try {
+ renderedComponent = this.render();
+ } catch (error) {
+ // IE8 requires `catch` in order to use `finally`.
+ throw error;
+ } finally {
+ ReactCurrentOwner.current = null;
+ }
+ invariant(
+ ReactComponent.isValidComponent(renderedComponent),
+ '%s.render(): A valid ReactComponent must be returned.',
+ this.constructor.displayName || 'ReactCompositeComponent'
+ );
+ return renderedComponent;
+ },
+
+ /**
+ * @private
+ */
+ _bindAutoBindMethods: function() {
+ for (var autoBindKey in this.__reactAutoBindMap) {
+ if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
+ continue;
+ }
+ var method = this.__reactAutoBindMap[autoBindKey];
+ this[autoBindKey] = this._bindAutoBindMethod(method);
+ }
+ },
+
+ /**
+ * Binds a method to the component.
+ *
+ * @param {function} method Method to be bound.
+ * @private
+ */
+ _bindAutoBindMethod: function(method) {
+ var component = this;
+ var boundMethod = function() {
+ return method.apply(component, arguments);
+ };
+ if (true) {
+ var componentName = component.constructor.displayName;
+ var _bind = boundMethod.bind;
+ boundMethod.bind = function(newThis) {
+ // User is trying to bind() an autobound method; we effectively will
+ // ignore the value of "this" that the user is trying to use, so
+ // let's warn.
+ if (newThis !== component) {
+ console.warn(
+ 'bind(): React component methods may only be bound to the ' +
+ 'component instance. See ' + componentName
+ );
+ } else if (arguments.length === 1) {
+ console.warn(
+ 'bind(): You are binding a component method to the component. ' +
+ 'React does this for you automatically in a high-performance ' +
+ 'way, so you can safely remove this call. See ' + componentName
+ );
+ return boundMethod;
+ }
+ return _bind.apply(boundMethod, arguments);
+ };
+ }
+ return boundMethod;
+ }
+};
+
+var ReactCompositeComponentBase = function() {};
+mixInto(ReactCompositeComponentBase, ReactComponent.Mixin);
+mixInto(ReactCompositeComponentBase, ReactOwner.Mixin);
+mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin);
+mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin);
+
+/**
+ * Module for creating composite components.
+ *
+ * @class ReactCompositeComponent
+ * @extends ReactComponent
+ * @extends ReactOwner
+ * @extends ReactPropTransferer
+ */
+var ReactCompositeComponent = {
+
+ LifeCycle: CompositeLifeCycle,
+
+ Base: ReactCompositeComponentBase,
+
+ /**
+ * Creates a composite component class given a class specification.
+ *
+ * @param {object} spec Class specification (which must define `render`).
+ * @return {function} Component constructor function.
+ * @public
+ */
+ createClass: function(spec) {
+ var Constructor = function() {};
+ Constructor.prototype = new ReactCompositeComponentBase();
+ Constructor.prototype.constructor = Constructor;
+ mixSpecIntoComponent(Constructor, spec);
+ invariant(
+ Constructor.prototype.render,
+ 'createClass(...): Class specification must implement a `render` method.'
+ );
+ // Reduce time spent doing lookups by setting these on the prototype.
+ for (var methodName in ReactCompositeComponentInterface) {
+ if (!Constructor.prototype[methodName]) {
+ Constructor.prototype[methodName] = null;
+ }
+ }
+
+ var ConvenienceConstructor = function(props, children) {
+ var instance = new Constructor();
+ instance.construct.apply(instance, arguments);
+ return instance;
+ };
+ ConvenienceConstructor.componentConstructor = Constructor;
+ ConvenienceConstructor.originalSpec = spec;
+ return ConvenienceConstructor;
+ },
+
+ /**
+ * TODO: Delete this when all callers have been updated to rely on this
+ * behavior being the default.
+ *
+ * Backwards compatible stub for what is now the default behavior.
+ * @param {function} method Method to be bound.
+ * @public
+ */
+ autoBind: function(method) {
+ if (true) {
+ console.warn(
+ 'React.autoBind() is now deprecated. All React component methods ' +
+ 'are auto bound by default, so React.autoBind() is a no-op. It ' +
+ 'will be removed in the next version of React'
+ );
+ }
+ return method;
+ }
+};
+
+module.exports = ReactCompositeComponent;
+
+})()
+},{"./ReactComponent":23,"./ReactCurrentOwner":25,"./ReactOwner":43,"./ReactPropTransferer":44,"./ReactUpdates":49,"./invariant":78,"./keyMirror":81,"./merge":84,"./mixInto":87}],25:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ReactCurrentOwner
+ */
+
+"use strict";
+
+/**
+ * Keeps track of the current owner.
+ *
+ * The current owner is the component who should own any components that are
+ * currently being constructed.
+ *
+ * The depth indicate how many composite components are above this render level.
+ */
+var ReactCurrentOwner = {
+
+ /**
+ * @internal
+ * @type {ReactComponent}
+ */
+ current: null
+
+};
+
+module.exports = ReactCurrentOwner;
+
+},{}],26:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ReactDOM
+ * @typechecks static-only
+ */
+
+"use strict";
+
+var ReactNativeComponent = require("./ReactNativeComponent");
+
+var mergeInto = require("./mergeInto");
+var objMapKeyVal = require("./objMapKeyVal");
+
+/**
+ * Creates a new React class that is idempotent and capable of containing other
+ * React components. It accepts event listeners and DOM properties that are
+ * valid according to `DOMProperty`.
+ *
+ * - Event listeners: `onClick`, `onMouseDown`, etc.
+ * - DOM properties: `className`, `name`, `title`, etc.
+ *
+ * The `style` property functions differently from the DOM API. It accepts an
+ * object mapping of style properties to values.
+ *
+ * @param {string} tag Tag name (e.g. `div`).
+ * @param {boolean} omitClose True if the close tag should be omitted.
+ * @private
+ */
+function createDOMComponentClass(tag, omitClose) {
+ var Constructor = function() {};
+ Constructor.prototype = new ReactNativeComponent(tag, omitClose);
+ Constructor.prototype.constructor = Constructor;
+
+ var ConvenienceConstructor = function(props, children) {
+ var instance = new Constructor();
+ instance.construct.apply(instance, arguments);
+ return instance;
+ };
+ ConvenienceConstructor.componentConstructor = Constructor;
+ return ConvenienceConstructor;
+}
+
+/**
+ * Creates a mapping from supported HTML tags to `ReactNativeComponent` classes.
+ * This is also accessible via `React.DOM`.
+ *
+ * @public
+ */
+var ReactDOM = objMapKeyVal({
+ a: false,
+ abbr: false,
+ address: false,
+ area: false,
+ article: false,
+ aside: false,
+ audio: false,
+ b: false,
+ base: false,
+ bdi: false,
+ bdo: false,
+ big: false,
+ blockquote: false,
+ body: false,
+ br: true,
+ button: false,
+ canvas: false,
+ caption: false,
+ cite: false,
+ code: false,
+ col: true,
+ colgroup: false,
+ data: false,
+ datalist: false,
+ dd: false,
+ del: false,
+ details: false,
+ dfn: false,
+ div: false,
+ dl: false,
+ dt: false,
+ em: false,
+ embed: true,
+ fieldset: false,
+ figcaption: false,
+ figure: false,
+ footer: false,
+ form: false, // NOTE: Injected, see `ReactDOMForm`.
+ h1: false,
+ h2: false,
+ h3: false,
+ h4: false,
+ h5: false,
+ h6: false,
+ head: false,
+ header: false,
+ hr: true,
+ html: false,
+ i: false,
+ iframe: false,
+ img: true,
+ input: true,
+ ins: false,
+ kbd: false,
+ keygen: true,
+ label: false,
+ legend: false,
+ li: false,
+ link: false,
+ main: false,
+ map: false,
+ mark: false,
+ menu: false,
+ menuitem: false, // NOTE: Close tag should be omitted, but causes problems.
+ meta: true,
+ meter: false,
+ nav: false,
+ noscript: false,
+ object: false,
+ ol: false,
+ optgroup: false,
+ option: false,
+ output: false,
+ p: false,
+ param: true,
+ pre: false,
+ progress: false,
+ q: false,
+ rp: false,
+ rt: false,
+ ruby: false,
+ s: false,
+ samp: false,
+ script: false,
+ section: false,
+ select: false,
+ small: false,
+ source: false,
+ span: false,
+ strong: false,
+ style: false,
+ sub: false,
+ summary: false,
+ sup: false,
+ table: false,
+ tbody: false,
+ td: false,
+ textarea: false, // NOTE: Injected, see `ReactDOMTextarea`.
+ tfoot: false,
+ th: false,
+ thead: false,
+ time: false,
+ title: false,
+ tr: false,
+ track: true,
+ u: false,
+ ul: false,
+ 'var': false,
+ video: false,
+ wbr: false,
+
+ // SVG
+ circle: false,
+ g: false,
+ line: false,
+ path: false,
+ polyline: false,
+ rect: false,
+ svg: false,
+ text: false
+}, createDOMComponentClass);
+
+var injection = {
+ injectComponentClasses: function(componentClasses) {
+ mergeInto(ReactDOM, componentClasses);
+ }
+};
+
+ReactDOM.injection = injection;
+
+module.exports = ReactDOM;
+
+},{"./ReactNativeComponent":41,"./mergeInto":86,"./objMapKeyVal":88}],27:[function(require,module,exports){
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule ReactDOMForm
+ */
+
+"use strict";
+
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactDOM = require("./ReactDOM");
+var ReactEventEmitter = require("./ReactEventEmitter");
+var EventConstants = require("./EventConstants");
+
+// Store a reference to the